Merge "Add logic to re-raise ANR dialogs if the user taps wait."
diff --git a/Android.bp b/Android.bp
index f06c35b..3afd6ec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -101,6 +101,7 @@
         // AIDL sources from external directories
         ":android.hardware.security.keymint-V1-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
+        ":android.hardware.tv.tuner-V1-java-source",
         ":android.security.apc-java-source",
         ":android.security.authorization-java-source",
         ":android.security.legacykeystore-java-source",
@@ -250,8 +251,6 @@
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
-        "android.hardware.tv.tuner-V1.0-java-constants",
-        "android.hardware.tv.tuner-V1.1-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
@@ -297,6 +296,7 @@
         ],
         include_dirs: [
             "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
             "packages/modules/Connectivity/framework/aidl-export",
         ],
     },
@@ -330,6 +330,7 @@
     ],
     sdk_version: "core_platform",
     static_libs: [
+        "android.hardware.common.fmq-V1-java",
         // TODO(b/184162091)
         "android.hardware.soundtrigger3-V1-java",
         "bouncycastle-repackaged-unbundled",
@@ -542,6 +543,7 @@
         ],
         include_dirs: [
             "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
             "packages/modules/Connectivity/framework/aidl-export",
         ],
     },
@@ -557,8 +559,6 @@
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
-        "android.hardware.tv.tuner-V1.0-java-constants",
-        "android.hardware.tv.tuner-V1.1-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb.gadget-V1.0-java",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 8cfc024..48ae723 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -113,7 +113,10 @@
     // TODO(b/169090544): remove below aidl includes.
     aidl: {
         local_include_dirs: ["media/aidl"],
-        include_dirs: ["frameworks/av/aidl"],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+        ],
     },
 }
 
@@ -200,7 +203,10 @@
     // TODO(b/169090544): remove below aidl includes.
     aidl: {
         local_include_dirs: ["media/aidl"],
-        include_dirs: ["frameworks/av/aidl"],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+        ],
     },
 }
 
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 5a04ba3..faf61a7 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -85,10 +85,7 @@
 
     @After
     public void tearDown() {
-        // TODO: Add a blob_store shell command to trigger idle maintenance to avoid hardcoding
-        // job id like this.
-        // From BlobStoreConfig.IDLE_JOB_ID = 191934935.
-        runShellCommand("cmd jobscheduler run -f android 191934935");
+        runShellCommand("cmd blob_store idle-maintenance");
     }
 
     @Test
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
index d07ed37..ecc5112 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -84,18 +84,18 @@
 
     @Override
     public void onDisconnected() {
-        Log.i(TAG, "onDisconnected: sServiceWatcher=" + sServiceWatcher);
-
-        if (sServiceWatcher == null) {
+        final ServiceWatcher sw = sServiceWatcher;
+        Log.i(TAG, "onDisconnected: sServiceWatcher=" + sw);
+        if (sw == null) {
             Log.e(TAG, "onDisconnected() without a watcher");
             return;
         }
-        if (sServiceWatcher.mService == null) {
-            Log.e(TAG, "onDisconnected(): no service on " + sServiceWatcher);
+        if (sw.mService == null) {
+            Log.e(TAG, "onDisconnected(): no service on " + sw);
             return;
         }
 
-        sServiceWatcher.mDestroyed.countDown();
+        sw.mDestroyed.countDown();
         clearServiceWatcher();
     }
 
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index 0e76488..fc70219 100644
--- a/apct-tests/perftests/packagemanager/Android.bp
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -20,6 +20,7 @@
         "androidx.annotation_annotation",
         "apct-perftests-utils",
         "collector-device-lib-platform",
+        "cts-install-lib-java",
     ],
 
     libs: ["android.test.base"],
diff --git a/apct-tests/perftests/packagemanager/AndroidManifest.xml b/apct-tests/perftests/packagemanager/AndroidManifest.xml
index 4bcd557..3b9431f 100644
--- a/apct-tests/perftests/packagemanager/AndroidManifest.xml
+++ b/apct-tests/perftests/packagemanager/AndroidManifest.xml
@@ -17,6 +17,12 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.perftests.packagemanager">
+    <!-- prevent test application from being obscured because of package visibility -->
+    <queries>
+        <package android:name="com.android.cts.install.lib.testapp.A" />
+        <package android:name="com.android.cts.install.lib.testapp.B" />
+        <package android:name="com.android.cts.install.lib.testapp.C" />
+    </queries>
 
     <permission android:name="com.android.perftests.packagemanager.TestPermission" />
     <uses-permission android:name="com.android.perftests.packagemanager.TestPermission" />
diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml
index 4903510..c9d45a6 100644
--- a/apct-tests/perftests/packagemanager/AndroidTest.xml
+++ b/apct-tests/perftests/packagemanager/AndroidTest.xml
@@ -130,6 +130,10 @@
         <option name="instrumentation-arg" key="perfetto_config_file"
                 value="trace_config.textproto"/>
 
+        <!--
+         PackageInstallerBenchmark will break for 5 minutes time out so it changes to 10 minutes
+          -->
+        <option name="test-timeout" value="600000" />
     </test>
 
 
diff --git a/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java b/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java
new file mode 100644
index 0000000..3b4f72b
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/src/android/content/pm/PackageInstallerBenchmark.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.HandlerThread;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.LocalIntentSender;
+import com.android.cts.install.lib.TestApp;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class PackageInstallerBenchmark {
+    private static final String TAG = "PackageInstallerBenchmark";
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    /**
+     * This rule adopts the Shell process permissions, needed because INSTALL_PACKAGES
+     * and DELETE_PACKAGES are privileged permission.
+     */
+    @Rule
+    public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
+            InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.DELETE_PACKAGES);
+
+    private static class SessionCallback extends PackageInstaller.SessionCallback {
+        private final List<Integer> mExpectedSessions;
+        private final CountDownLatch mCountDownLatch;
+        private final boolean mExpectedSuccess;
+
+        SessionCallback(boolean expectedSuccess, List<Integer> expectedSessions,
+                @NonNull CountDownLatch countDownLatch) {
+            mExpectedSuccess = expectedSuccess;
+            mCountDownLatch = countDownLatch;
+            mExpectedSessions = expectedSessions;
+        }
+
+        @Override
+        public void onCreated(int sessionId) { }
+
+        @Override
+        public void onBadgingChanged(int sessionId) { }
+
+        @Override
+        public void onActiveChanged(int sessionId, boolean active) { }
+
+        @Override
+        public void onProgressChanged(int sessionId, float progress) { }
+
+        @Override
+        public void onFinished(int sessionId, boolean success) {
+            if (success == mExpectedSuccess && mExpectedSessions.contains(sessionId)) {
+                mCountDownLatch.countDown();
+            }
+        }
+    }
+
+    private CountDownLatch mCountDownLatch;
+    private SessionCallback mSessionCallback;
+    private PackageInstaller mPackageInstaller;
+    private Install mInstall;
+    private HandlerThread mHandlerThread;
+    private List<PackageInstaller.Session> mExpectedSessions;
+    private List<Integer> mExpectedSessionIds;
+    final LocalIntentSender mLocalIntentSender = new LocalIntentSender();
+    private IntentSender mIntentSender;
+
+    @Before
+    public void setUp() throws IOException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mPackageInstaller =  context.getPackageManager().getPackageInstaller();
+        mHandlerThread = new HandlerThread("PackageInstallerBenchmark");
+        mHandlerThread.start();
+
+        mIntentSender = mLocalIntentSender.getIntentSender();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        context.unregisterReceiver(mLocalIntentSender);
+
+        uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
+        mHandlerThread.quitSafely();
+    }
+
+    private List<PackageInstaller.Session> createSinglePackageSessions(
+            BenchmarkState state, boolean expectedResult, TestApp...testApps)
+            throws IOException, InterruptedException {
+        state.pauseTiming();
+        uninstall(false /* stop at fail */, testApps);
+
+        mExpectedSessions = new ArrayList<>();
+        mExpectedSessionIds = new ArrayList<>();
+        for (TestApp testApp : testApps) {
+            mInstall = Install.single(testApp);
+            final int expectedSessionId = mInstall.createSession();
+            PackageInstaller.Session session =
+                    InstallUtils.openPackageInstallerSession(expectedSessionId);
+            Log.d(TAG, "createNewSession: session expectedSessionId = " + expectedSessionId);
+            mExpectedSessions.add(session);
+            mExpectedSessionIds.add(expectedSessionId);
+        }
+
+        mCountDownLatch = new CountDownLatch(mExpectedSessions.size());
+        mSessionCallback = new SessionCallback(expectedResult, mExpectedSessionIds,
+                mCountDownLatch);
+        mPackageInstaller.registerSessionCallback(mSessionCallback,
+                mHandlerThread.getThreadHandler());
+        state.resumeTiming();
+        return mExpectedSessions;
+    }
+
+    private List<PackageInstaller.Session> createMultiplePackageSessions(BenchmarkState state,
+            boolean expectedSuccess, List<TestApp[]> testAppsList)
+            throws IOException, InterruptedException {
+        state.pauseTiming();
+        mExpectedSessions = new ArrayList<>();
+        mExpectedSessionIds = new ArrayList<>();
+        for (TestApp[] testApps : testAppsList) {
+            uninstall(false /* stop at fail */, testApps);
+
+            mInstall = Install.multi(testApps);
+            final int expectedSessionId = mInstall.createSession();
+            PackageInstaller.Session session =
+                    InstallUtils.openPackageInstallerSession(expectedSessionId);
+            mExpectedSessions.add(session);
+            mExpectedSessionIds.add(expectedSessionId);
+        }
+
+        mCountDownLatch = new CountDownLatch(mExpectedSessions.size());
+        mSessionCallback = new SessionCallback(expectedSuccess, mExpectedSessionIds,
+                mCountDownLatch);
+        mPackageInstaller.registerSessionCallback(mSessionCallback,
+                mHandlerThread.getThreadHandler());
+        state.resumeTiming();
+        return mExpectedSessions;
+    }
+
+    private void uninstall(boolean stopAtFail, TestApp...testApps) throws InterruptedException {
+        String[] packageNames = new String[testApps.length];
+        for (int i = 0; i < testApps.length; i++) {
+            packageNames[i] = testApps[i].getPackageName();
+        }
+        uninstall(stopAtFail, packageNames);
+    }
+
+    private void uninstall(boolean stopAtFail, String...packageNames) throws InterruptedException {
+        LocalIntentSender localIntentSender = new LocalIntentSender();
+        IntentSender intentSender = localIntentSender.getIntentSender();
+        for (String packageName : packageNames) {
+            try {
+                mPackageInstaller.uninstall(packageName, intentSender);
+            } catch (IllegalArgumentException e) {
+                continue;
+            }
+            Intent intent = localIntentSender.getResult();
+            if (stopAtFail) {
+                InstallUtils.assertStatusSuccess(intent);
+            }
+        }
+
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        context.unregisterReceiver(localIntentSender);
+    }
+
+    private void uninstallSession(BenchmarkState state, String...packageNames)
+            throws InterruptedException {
+        state.pauseTiming();
+        uninstall(true /* stop at fail */, packageNames);
+        mPackageInstaller.unregisterSessionCallback(mSessionCallback);
+        state.resumeTiming();
+    }
+
+    @Test(timeout = 600_000L)
+    public void commit_aSingleApkSession_untilFinishBenchmark() throws Exception {
+        uninstall(false /* stop at fail */, TestApp.A);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            List<PackageInstaller.Session> sessions =
+                    createSinglePackageSessions(state, true, TestApp.A1);
+
+            for (PackageInstaller.Session session : sessions) {
+                session.commit(mIntentSender);
+            }
+            mCountDownLatch.await(1, TimeUnit.MINUTES);
+
+            uninstallSession(state, TestApp.A);
+        }
+    }
+
+    @Test(timeout = 600_000L)
+    public void commit_threeSingleApkSessions_untilFinishBenchmark() throws Exception {
+        uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            List<PackageInstaller.Session> sessions = createSinglePackageSessions(
+                    state, true, TestApp.A1, TestApp.B1, TestApp.C1);
+
+            for (PackageInstaller.Session session : sessions) {
+                session.commit(mIntentSender);
+            }
+            mCountDownLatch.await(1, TimeUnit.MINUTES);
+
+            uninstallSession(state, TestApp.A, TestApp.B, TestApp.C);
+        }
+    }
+
+    @Test(timeout = 600_000L)
+    public void commit_aMultiplePackagesSession_untilFinishBenchmark()
+            throws IOException, InterruptedException {
+        uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final List<TestApp[]> multiPackageApps = new ArrayList<>();
+        multiPackageApps.add(new TestApp[] {TestApp.A1, TestApp.B1, TestApp.C1});
+
+        while (state.keepRunning()) {
+            List<PackageInstaller.Session> sessions = createMultiplePackageSessions(
+                    state, true, multiPackageApps);
+
+            for (PackageInstaller.Session session : sessions) {
+                session.commit(mIntentSender);
+            }
+            mCountDownLatch.await(1, TimeUnit.MINUTES);
+
+            uninstallSession(state, TestApp.A, TestApp.B, TestApp.C);
+        }
+    }
+
+    @Test(timeout = 600_000L)
+    public void commit_threeMultiplePackageSessions_untilFinishBenchmark()
+            throws Exception {
+        uninstall(false /* stop at fail */, TestApp.A, TestApp.B, TestApp.C);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final List<TestApp[]> multiPackageApps = new ArrayList<>();
+        multiPackageApps.add(new TestApp[] {TestApp.A1});
+        multiPackageApps.add(new TestApp[] {TestApp.B1});
+        multiPackageApps.add(new TestApp[] {TestApp.C1});
+
+        while (state.keepRunning()) {
+            List<PackageInstaller.Session> sessions = createMultiplePackageSessions(
+                    state, true, multiPackageApps);
+
+            for (PackageInstaller.Session session : sessions) {
+                session.commit(mIntentSender);
+            }
+            mCountDownLatch.await(1, TimeUnit.MINUTES);
+
+            uninstallSession(state, TestApp.A, TestApp.B, TestApp.C);
+        }
+    }
+
+    @Test(timeout = 600_000L)
+    public void commit_aMultipleApksSession_untilFinishBenchmark()
+            throws IOException, InterruptedException {
+        uninstall(false /* stop at fail */, TestApp.A);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            List<PackageInstaller.Session> sessions = createSinglePackageSessions(
+                    state, true, TestApp.ASplit1);
+
+            for (PackageInstaller.Session session : sessions) {
+                session.commit(mIntentSender);
+            }
+            mCountDownLatch.await(1, TimeUnit.MINUTES);
+
+            uninstallSession(state, TestApp.A);
+        }
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
index fe2b1f6..ebd8d86 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -306,27 +306,28 @@
 
     private void fillStatus(Bundle status, String key, Stats stats) {
         if (shouldReport(StatsReport.FLAG_ITERATION)) {
-            status.putLong(key + "_iteration", stats.getSize());
+            status.putLong(key + "_iteration (ns)", stats.getSize());
         }
         if (shouldReport(StatsReport.FLAG_MEDIAN)) {
-            status.putLong(key + "_median", stats.getMedian());
+            status.putLong(key + "_median (ns)", stats.getMedian());
         }
         if (shouldReport(StatsReport.FLAG_MEAN)) {
-            status.putLong(key + "_mean", Math.round(stats.getMean()));
+            status.putLong(key + "_mean (ns)", Math.round(stats.getMean()));
         }
         if (shouldReport(StatsReport.FLAG_MIN)) {
-            status.putLong(key + "_min", stats.getMin());
+            status.putLong(key + "_min (ns)", stats.getMin());
         }
         if (shouldReport(StatsReport.FLAG_MAX)) {
-            status.putLong(key + "_max", stats.getMax());
+            status.putLong(key + "_max (ns)", stats.getMax());
         }
         if (mStatsReportPercentiles != null) {
             for (int percentile : mStatsReportPercentiles) {
-                status.putLong(key + "_percentile" + percentile, stats.getPercentile(percentile));
+                status.putLong(key + "_percentile" + percentile + " (ns)",
+                        stats.getPercentile(percentile));
             }
         }
         if (shouldReport(StatsReport.FLAG_STDDEV)) {
-            status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation()));
+            status.putLong(key + "_stddev (ns)", Math.round(stats.getStandardDeviation()));
         }
         if (shouldReport(StatsReport.FLAG_COEFFICIENT_VAR)) {
             status.putLong(key + "_cv",
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
index 6e4a5a0..7b287d5 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.app.JobSchedulerImpl;
 import android.app.SystemServiceRegistry;
+import android.app.tare.EconomyManager;
 import android.content.Context;
 import android.os.DeviceIdleManager;
 import android.os.IDeviceIdleController;
@@ -56,5 +57,7 @@
         SystemServiceRegistry.registerContextAwareService(
                 Context.POWER_EXEMPTION_SERVICE, PowerExemptionManager.class,
                 PowerExemptionManager::new);
+        SystemServiceRegistry.registerStaticService(
+                Context.RESOURCE_ECONOMY_SERVICE, EconomyManager.class, EconomyManager::new);
     }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
new file mode 100644
index 0000000..4053bdd
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.tare;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * Provides access to the resource economy service.
+ *
+ * @hide
+ */
+@SystemService(Context.RESOURCE_ECONOMY_SERVICE)
+public class EconomyManager {
+    // Keys for AlarmManager TARE factors
+    /** @hide */
+    public static final String KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED =
+            "am_min_satiated_balance_exempted";
+    /** @hide */
+    public static final String KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP =
+            "am_min_satiated_balance_headless_system_app";
+    /** @hide */
+    public static final String KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP =
+            "am_min_satiated_balance_other_app";
+    /** @hide */
+    public static final String KEY_AM_MAX_SATIATED_BALANCE = "am_max_satiated_balance";
+    /** @hide */
+    public static final String KEY_AM_MAX_CIRCULATION = "am_max_circulation";
+    // TODO: Add AlarmManager modifier keys
+    /** @hide */
+    public static final String KEY_AM_REWARD_TOP_ACTIVITY_INSTANT =
+            "am_reward_top_activity_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_TOP_ACTIVITY_ONGOING =
+            "am_reward_top_activity_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_TOP_ACTIVITY_MAX = "am_reward_top_activity_max";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT =
+            "am_reward_notification_seen_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING =
+            "am_reward_notification_seen_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_MAX =
+            "am_reward_notification_seen_max";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT =
+            "am_reward_notification_seen_within_15_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING =
+            "am_reward_notification_seen_within_15_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX =
+            "am_reward_notification_seen_within_15_max";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT =
+            "am_reward_notification_interaction_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING =
+            "am_reward_notification_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX =
+            "am_reward_notification_interaction_max";
+    /** @hide */
+    public static final String KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT =
+            "am_reward_widget_interaction_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING =
+            "am_reward_widget_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_WIDGET_INTERACTION_MAX =
+            "am_reward_widget_interaction_max";
+    /** @hide */
+    public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT =
+            "am_reward_other_user_interaction_instant";
+    /** @hide */
+    public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING =
+            "am_reward_other_user_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX =
+            "am_reward_other_user_interaction_max";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP =
+            "am_action_alarm_allow_while_idle_exact_wakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP =
+            "am_action_alarm_allow_while_idle_inexact_wakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP =
+            "am_action_alarm_exact_wakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP =
+            "am_action_alarm_inexact_wakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP =
+            "am_action_alarm_allow_while_idle_exact_nonwakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP =
+            "am_action_alarm_exact_nonwakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP =
+            "am_action_alarm_allow_while_idle_inexact_nonwakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP =
+            "am_action_alarm_inexact_nonwakeup_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP =
+            "am_action_alarm_alarmclock_ctp";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE =
+            "am_action_alarm_allow_while_idle_exact_wakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE =
+            "am_action_alarm_allow_while_idle_inexact_wakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE =
+            "am_action_alarm_exact_wakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE =
+            "am_action_alarm_inexact_wakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE =
+            "am_action_alarm_allow_while_idle_exact_nonwakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE =
+            "am_action_alarm_exact_nonwakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE =
+            "am_action_alarm_allow_while_idle_inexact_nonwakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE =
+            "am_action_alarm_inexact_nonwakeup_base_price";
+    /** @hide */
+    public static final String KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE =
+            "am_action_alarm_alarmclock_base_price";
+
+// Keys for JobScheduler TARE factors
+    /** @hide */
+    public static final String KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED =
+            "js_min_satiated_balance_exempted";
+    /** @hide */
+    public static final String KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP =
+            "js_min_satiated_balance_headless_system_app";
+    /** @hide */
+    public static final String KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP =
+            "js_min_satiated_balance_other_app";
+    /** @hide */
+    public static final String KEY_JS_MAX_SATIATED_BALANCE =
+            "js_max_satiated_balance";
+    /** @hide */
+    public static final String KEY_JS_MAX_CIRCULATION = "js_max_circulation";
+    // TODO: Add JobScheduler modifier keys
+    /** @hide */
+    public static final String KEY_JS_REWARD_TOP_ACTIVITY_INSTANT =
+            "js_reward_top_activity_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_TOP_ACTIVITY_ONGOING =
+            "js_reward_top_activity_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_TOP_ACTIVITY_MAX =
+            "js_reward_top_activity_max";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT =
+            "js_reward_notification_seen_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING =
+            "js_reward_notification_seen_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_MAX =
+            "js_reward_notification_seen_max";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT =
+            "js_reward_notification_interaction_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING =
+            "js_reward_notification_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX =
+            "js_reward_notification_interaction_max";
+    /** @hide */
+    public static final String KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT =
+            "js_reward_widget_interaction_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING =
+            "js_reward_widget_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_WIDGET_INTERACTION_MAX =
+            "js_reward_widget_interaction_max";
+    /** @hide */
+    public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT =
+            "js_reward_other_user_interaction_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING =
+            "js_reward_other_user_interaction_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX =
+            "js_reward_other_user_interaction_max";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MAX_START_CTP = "js_action_job_max_start_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MAX_RUNNING_CTP = "js_action_job_max_running_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_HIGH_START_CTP = "js_action_job_high_start_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP =
+            "js_action_job_high_running_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_DEFAULT_START_CTP =
+            "js_action_job_default_start_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP =
+            "js_action_job_default_running_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_LOW_START_CTP = "js_action_job_low_start_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_LOW_RUNNING_CTP = "js_action_job_low_running_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MIN_START_CTP = "js_action_job_min_start_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MIN_RUNNING_CTP = "js_action_job_min_running_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP =
+            "js_action_job_timeout_penalty_ctp";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE =
+            "js_action_job_max_start_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE =
+            "js_action_job_max_running_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE =
+            "js_action_job_high_start_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE =
+            "js_action_job_high_running_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE =
+            "js_action_job_default_start_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE =
+            "js_action_job_default_running_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE =
+            "js_action_job_low_start_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE =
+            "js_action_job_low_running_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE =
+            "js_action_job_min_start_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE =
+            "js_action_job_min_running_base_price";
+    /** @hide */
+    public static final String KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE =
+            "js_action_job_timeout_penalty_base_price";
+
+    // Default values AlarmManager factors
+    /** @hide */
+    public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP = 200;
+    /** @hide */
+    public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP = 160;
+    /** @hide */
+    public static final int DEFAULT_AM_MAX_SATIATED_BALANCE = 1440;
+    /** @hide */
+    public static final int DEFAULT_AM_MAX_CIRCULATION = 52000;
+    // TODO: add AlarmManager modifier default values
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT = 0;
+    /** @hide */
+    public static final double DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX = 60;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT = 5;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT = 5;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT = 10;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT = 10;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX = 500;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP = 1;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP = 1;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP = 1;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP = 1;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP = 5;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE = 5;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE = 4;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE = 4;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE = 3;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE = 2;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE =
+            2;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE = 1;
+    /** @hide */
+    public static final int DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE = 10;
+
+    // Default values JobScheduler factors
+    // TODO: add time_since_usage variable to min satiated balance factors
+    /** @hide */
+    public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED = 50000;
+    /** @hide */
+    public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP = 10000;
+    /** @hide */
+    public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP = 2000;
+    /** @hide */
+    public static final int DEFAULT_JS_MAX_SATIATED_BALANCE = 60000;
+    /** @hide */
+    public static final int DEFAULT_JS_MAX_CIRCULATION = 691200;
+    // TODO: add JobScheduler modifier default values
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT = 0;
+    /** @hide */
+    public static final double DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX = 15000;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT = 1;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX = 10;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT = 5;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX = 5000;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT = 10;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX = 5000;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT = 10;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING = 0;
+    /** @hide */
+    public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX = 5000;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MAX_START_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_HIGH_START_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_LOW_START_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MIN_START_CTP = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP = 30;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE = 10;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE = 5;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE = 8;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE = 4;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE = 6;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE = 3;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE = 4;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE = 2;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE = 1;
+    /** @hide */
+    public static final int DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE = 60;
+}
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 86fa06c..9572808 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2603,7 +2603,7 @@
             final int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
             if (callingUid != uid && !UserHandle.isCore(callingUid)) {
                 throw new SecurityException("Uid " + callingUid
-                        + " cannot query hasScheduleExactAlarm for uid " + uid);
+                        + " cannot query hasScheduleExactAlarm for package " + packageName);
             }
             return (uid > 0) ? hasScheduleExactAlarmInternal(packageName, uid) : false;
         }
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 4fb0b71..f0745f3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -696,7 +696,6 @@
 
     @VisibleForTesting
     class PendingJobComparator implements Comparator<JobStatus> {
-        private final SparseBooleanArray mUidHasEjCache = new SparseBooleanArray();
         private final SparseLongArray mEarliestRegEnqueueTimeCache = new SparseLongArray();
 
         /**
@@ -705,14 +704,11 @@
         @GuardedBy("mLock")
         @VisibleForTesting
         void refreshLocked() {
-            mUidHasEjCache.clear();
             mEarliestRegEnqueueTimeCache.clear();
             for (int i = 0; i < mPendingJobs.size(); ++i) {
                 final JobStatus job = mPendingJobs.get(i);
                 final int uid = job.getSourceUid();
-                if (job.isRequestedExpeditedJob()) {
-                    mUidHasEjCache.put(uid, true);
-                } else {
+                if (!job.isRequestedExpeditedJob()) {
                     final long earliestEnqueueTime =
                             mEarliestRegEnqueueTimeCache.get(uid, Long.MAX_VALUE);
                     mEarliestRegEnqueueTimeCache.put(uid,
@@ -742,9 +738,7 @@
                     return o1EJ ? -1 : 1;
                 }
             }
-            final boolean uid1HasEj = mUidHasEjCache.get(o1.getSourceUid());
-            final boolean uid2HasEj = mUidHasEjCache.get(o2.getSourceUid());
-            if ((uid1HasEj || uid2HasEj) && (o1EJ || o2EJ)) {
+            if (o1EJ || o2EJ) {
                 // We MUST prioritize EJs ahead of regular jobs within a single app. Since we do
                 // that, in order to satisfy the transitivity constraint of the comparator, if
                 // any UID has an EJ, we must ensure that the EJ is ordered ahead of the regular
@@ -765,9 +759,13 @@
                     } else if (uid1EarliestRegEnqueueTime > uid2EarliestRegEnqueueTime) {
                         return 1;
                     }
-                } else if (o1EJ && uid1EarliestRegEnqueueTime < o2.enqueueTime) {
+                } else if (o1EJ && uid1EarliestRegEnqueueTime <= o2.enqueueTime) {
+                    // Include = to ensure that if we sorted an EJ ahead of a regular job at time X
+                    // then we make sure to sort it ahead of all regular jobs at time X.
                     return -1;
-                } else if (o2EJ && uid2EarliestRegEnqueueTime < o1.enqueueTime) {
+                } else if (o2EJ && uid2EarliestRegEnqueueTime <= o1.enqueueTime) {
+                    // Include = to ensure that if we sorted an EJ ahead of a regular job at time X
+                    // then we make sure to sort it ahead of all regular jobs at time X.
                     return 1;
                 }
             }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 76836e4..844a480 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -89,6 +89,7 @@
     static final int CONSTRAINT_TIMING_DELAY = 1<<31;
     static final int CONSTRAINT_DEADLINE = 1<<30;
     static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
+    static final int CONSTRAINT_TARE_WEALTH = 1 << 27; // Implicit constraint
     static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
     static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
     static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;      // Implicit constraint
@@ -146,6 +147,7 @@
     private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
             | CONSTRAINT_DEADLINE
             | CONSTRAINT_IDLE
+            | CONSTRAINT_TARE_WEALTH
             | CONSTRAINT_TIMING_DELAY
             | CONSTRAINT_WITHIN_QUOTA;
 
@@ -395,6 +397,10 @@
      * Whether or not this job is approved to be treated as expedited per quota policy.
      */
     private boolean mExpeditedQuotaApproved;
+    /**
+     * Whether or not this job is approved to be treated as expedited per TARE policy.
+     */
+    private boolean mExpeditedTareApproved;
 
     /////// Booleans that track if a job is ready to run. They should be updated whenever dependent
     /////// states change.
@@ -421,6 +427,9 @@
     /** The job is within its quota based on its standby bucket. */
     private boolean mReadyWithinQuota;
 
+    /** The job has enough credits to run based on TARE. */
+    private boolean mReadyTareWealth;
+
     /** The job's dynamic requirements have been satisfied. */
     private boolean mReadyDynamicSatisfied;
 
@@ -1230,6 +1239,16 @@
         return false;
     }
 
+    /** @return true if the constraint was changed, false otherwise. */
+    boolean setTareWealthConstraintSatisfied(final long nowElapsed, boolean state) {
+        if (setConstraintSatisfied(CONSTRAINT_TARE_WEALTH, nowElapsed, state)) {
+            // The constraint was changed. Update the ready flag.
+            mReadyTareWealth = state;
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Sets whether or not this job is approved to be treated as an expedited job based on quota
      * policy.
@@ -1245,6 +1264,21 @@
         return true;
     }
 
+    /**
+     * Sets whether or not this job is approved to be treated as an expedited job based on TARE
+     * policy.
+     *
+     * @return true if the approval bit was changed, false otherwise.
+     */
+    boolean setExpeditedJobTareApproved(final long nowElapsed, boolean state) {
+        if (mExpeditedTareApproved == state) {
+            return false;
+        }
+        mExpeditedTareApproved = state;
+        updateExpeditedDependencies();
+        return true;
+    }
+
     private void updateExpeditedDependencies() {
         // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
         // Making it also track requested-expedited jobs would add unnecessary hops since the
@@ -1353,6 +1387,7 @@
             case CONSTRAINT_DEVICE_NOT_DOZING:
                 return JobParameters.STOP_REASON_DEVICE_STATE;
 
+            case CONSTRAINT_TARE_WEALTH:
             case CONSTRAINT_WITHIN_QUOTA:
                 return JobParameters.STOP_REASON_QUOTA;
 
@@ -1405,6 +1440,11 @@
             Slog.wtf(TAG, "Tried to set quota as a dynamic constraint");
             constraints &= ~CONSTRAINT_WITHIN_QUOTA;
         }
+        if ((constraints & CONSTRAINT_TARE_WEALTH) != 0) {
+            // Quota should never be used as a dynamic constraint.
+            Slog.wtf(TAG, "Tried to set TARE as a dynamic constraint");
+            constraints &= ~CONSTRAINT_TARE_WEALTH;
+        }
 
         // Connectivity and content trigger are special since they're only valid to add if the
         // job has requested network or specific content URIs. Adding these constraints to jobs
@@ -1472,6 +1512,10 @@
                 oldValue = mReadyNotDozing;
                 mReadyNotDozing = value;
                 break;
+            case CONSTRAINT_TARE_WEALTH:
+                oldValue = mReadyTareWealth;
+                mReadyTareWealth = value;
+                break;
             case CONSTRAINT_WITHIN_QUOTA:
                 oldValue = mReadyWithinQuota;
                 mReadyWithinQuota = value;
@@ -1500,6 +1544,9 @@
             case CONSTRAINT_DEVICE_NOT_DOZING:
                 mReadyNotDozing = oldValue;
                 break;
+            case CONSTRAINT_TARE_WEALTH:
+                mReadyTareWealth = oldValue;
+                break;
             case CONSTRAINT_WITHIN_QUOTA:
                 mReadyWithinQuota = oldValue;
                 break;
@@ -1727,6 +1774,9 @@
         if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
             pw.print(" BACKGROUND_NOT_RESTRICTED");
         }
+        if ((constraints & CONSTRAINT_TARE_WEALTH) != 0) {
+            pw.print(" TARE_WEALTH");
+        }
         if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
             pw.print(" WITHIN_QUOTA");
         }
@@ -1991,7 +2041,8 @@
             pw.println();
             pw.print("Unsatisfied constraints:");
             dumpConstraints(pw,
-                    ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
+                    ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA | CONSTRAINT_TARE_WEALTH)
+                            & ~satisfiedConstraints));
             pw.println();
 
             pw.println("Constraint history:");
@@ -2050,6 +2101,8 @@
         if ((getFlags() & JobInfo.FLAG_EXPEDITED) != 0) {
             pw.print("expeditedQuotaApproved: ");
             pw.print(mExpeditedQuotaApproved);
+            pw.print(" expeditedTareApproved: ");
+            pw.print(mExpeditedTareApproved);
             pw.print(" (started as EJ: ");
             pw.print(startedAsExpeditedJob);
             pw.println(")");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index f0fc3b0..3fe8df2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -160,8 +160,8 @@
 
     public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate);
-    public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
-            Predicate<JobStatus> predicate);
+    public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+            Predicate<JobStatus> predicate) {}
 
     /** Dump any internal constants the Controller may have. */
     public void dumpConstants(IndentingPrintWriter pw) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
new file mode 100644
index 0000000..401646d
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job.controllers;
+
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
+import android.annotation.NonNull;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.tare.EconomyManagerInternal;
+import com.android.server.tare.EconomyManagerInternal.ActionBill;
+import com.android.server.tare.JobSchedulerEconomicPolicy;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * Controller that interfaces with Tare ({@link EconomyManagerInternal} and manages each job's
+ * ability to run per TARE policies.
+ *
+ * @see JobSchedulerEconomicPolicy
+ */
+public class TareController extends StateController {
+    private static final String TAG = "JobScheduler.TARE";
+    private static final boolean DEBUG = JobSchedulerService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
+     * eligible to run unless it can pay for a job start and at least some period of execution time.
+     */
+    private static final ActionBill BILL_JOB_START_DEFAULT =
+            new ActionBill(List.of(
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0),
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 30_000L)
+            ));
+
+    /**
+     * Bill to use when a default is currently running. We want to track and make sure the app can
+     * continue to pay for 1 more second of execution time. We stop the job when the app can no
+     * longer pay for that time.
+     */
+    private static final ActionBill BILL_JOB_RUNNING_DEFAULT =
+            new ActionBill(List.of(
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 1_000L)
+            ));
+
+    /**
+     * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
+     * eligible to run unless it can pay for a job start and at least some period of execution time.
+     */
+    private static final ActionBill BILL_JOB_START_EXPEDITED =
+            new ActionBill(List.of(
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0),
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 30_000L)
+            ));
+
+    /**
+     * Bill to use when an EJ is currently running (as an EJ). We want to track and make sure the
+     * app can continue to pay for 1 more second of execution time. We stop the job when the app can
+     * no longer pay for that time.
+     */
+    private static final ActionBill BILL_JOB_RUNNING_EXPEDITED =
+            new ActionBill(List.of(
+                    new EconomyManagerInternal.AnticipatedAction(
+                            JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 1_000L)
+            ));
+
+    private final EconomyManagerInternal mEconomyManagerInternal;
+
+    private final BackgroundJobsController mBackgroundJobsController;
+    private final ConnectivityController mConnectivityController;
+
+    /**
+     * Local cache of the ability of each userId-pkg to afford the various bills we're tracking for
+     * them.
+     */
+    @GuardedBy("mLock")
+    private final SparseArrayMap<String, ArrayMap<ActionBill, Boolean>> mAffordabilityCache =
+            new SparseArrayMap<>();
+
+    /**
+     * List of all tracked jobs. Out SparseArrayMap is userId-sourcePkg. The inner mapping is the
+     * anticipated actions and all the jobs that are applicable to them.
+     */
+    @GuardedBy("mLock")
+    private final SparseArrayMap<String, ArrayMap<ActionBill, ArraySet<JobStatus>>>
+            mRegisteredBillsAndJobs = new SparseArrayMap<>();
+
+    private final EconomyManagerInternal.AffordabilityChangeListener mAffordabilityChangeListener =
+            (userId, pkgName, bill, canAfford) -> {
+                final long nowElapsed = sElapsedRealtimeClock.millis();
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            userId + ":" + pkgName + " affordability for " + getBillName(bill)
+                                    + " changed to " + canAfford);
+                }
+                synchronized (mLock) {
+                    ArrayMap<ActionBill, Boolean> actionAffordability =
+                            mAffordabilityCache.get(userId, pkgName);
+                    if (actionAffordability == null) {
+                        actionAffordability = new ArrayMap<>();
+                        mAffordabilityCache.add(userId, pkgName, actionAffordability);
+                    }
+                    actionAffordability.put(bill, canAfford);
+
+                    final ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                            mRegisteredBillsAndJobs.get(userId, pkgName);
+                    if (billToJobMap != null) {
+                        final ArraySet<JobStatus> jobs = billToJobMap.get(bill);
+                        if (jobs != null) {
+                            final ArraySet<JobStatus> changedJobs = new ArraySet<>();
+                            for (int i = 0; i < jobs.size(); ++i) {
+                                final JobStatus job = jobs.valueAt(i);
+                                // Use hasEnoughWealth if canAfford is false in case the job has
+                                // other bills it can depend on (eg. EJs being demoted to
+                                // regular jobs).
+                                if (job.setTareWealthConstraintSatisfied(nowElapsed,
+                                        canAfford || hasEnoughWealthLocked(job))) {
+                                    changedJobs.add(job);
+                                }
+                                if (job.isRequestedExpeditedJob()
+                                        && setExpeditedTareApproved(job, nowElapsed,
+                                        canAffordExpeditedBillLocked(job))) {
+                                    changedJobs.add(job);
+                                }
+                            }
+                            if (changedJobs.size() > 0) {
+                                mStateChangedListener.onControllerStateChanged(changedJobs);
+                            }
+                        }
+                    }
+                }
+            };
+
+    @GuardedBy("mLock")
+    private boolean mIsEnabled;
+
+    public TareController(JobSchedulerService service,
+            @NonNull BackgroundJobsController backgroundJobsController,
+            @NonNull ConnectivityController connectivityController) {
+        super(service);
+        mBackgroundJobsController = backgroundJobsController;
+        mConnectivityController = connectivityController;
+        mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
+    }
+
+    @Override
+    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        jobStatus.setTareWealthConstraintSatisfied(nowElapsed, hasEnoughWealthLocked(jobStatus));
+        setExpeditedTareApproved(jobStatus, nowElapsed,
+                jobStatus.isRequestedExpeditedJob() && canAffordExpeditedBillLocked(jobStatus));
+
+        final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus);
+        for (int i = 0; i < bills.size(); ++i) {
+            addJobToBillList(jobStatus, bills.valueAt(i));
+        }
+    }
+
+    @Override
+    public void prepareForExecutionLocked(JobStatus jobStatus) {
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                mRegisteredBillsAndJobs.get(userId, pkgName);
+        if (billToJobMap == null) {
+            Slog.e(TAG, "Job is being prepared but doesn't have a pre-existing billToJobMap");
+        } else {
+            for (int i = 0; i < billToJobMap.size(); ++i) {
+                removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
+            }
+        }
+        if (jobStatus.shouldTreatAsExpeditedJob()) {
+            addJobToBillList(jobStatus, BILL_JOB_RUNNING_EXPEDITED);
+        }
+        addJobToBillList(jobStatus, BILL_JOB_RUNNING_DEFAULT);
+    }
+
+    @Override
+    public void unprepareFromExecutionLocked(JobStatus jobStatus) {
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus);
+        ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                mRegisteredBillsAndJobs.get(userId, pkgName);
+        if (billToJobMap == null) {
+            Slog.e(TAG, "Job was just unprepared but didn't have a pre-existing billToJobMap");
+        } else {
+            for (int i = 0; i < billToJobMap.size(); ++i) {
+                removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
+            }
+        }
+        for (int i = 0; i < bills.size(); ++i) {
+            addJobToBillList(jobStatus, bills.valueAt(i));
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
+            boolean forUpdate) {
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                mRegisteredBillsAndJobs.get(userId, pkgName);
+        if (billToJobMap != null) {
+            for (int i = 0; i < billToJobMap.size(); ++i) {
+                removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    public boolean canScheduleEJ(@NonNull JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return true;
+        }
+        return canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED);
+    }
+
+    @GuardedBy("mLock")
+    private void addJobToBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                mRegisteredBillsAndJobs.get(userId, pkgName);
+        if (billToJobMap == null) {
+            billToJobMap = new ArrayMap<>();
+            mRegisteredBillsAndJobs.add(userId, pkgName, billToJobMap);
+        }
+        ArraySet<JobStatus> jobs = billToJobMap.get(bill);
+        if (jobs == null) {
+            jobs = new ArraySet<>();
+            billToJobMap.put(bill, jobs);
+        }
+        if (jobs.add(jobStatus)) {
+            mEconomyManagerInternal.registerAffordabilityChangeListener(userId, pkgName,
+                    mAffordabilityChangeListener, bill);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void removeJobFromBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        final ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
+                mRegisteredBillsAndJobs.get(userId, pkgName);
+        if (billToJobMap != null) {
+            final ArraySet<JobStatus> jobs = billToJobMap.get(bill);
+            if (jobs == null || (jobs.remove(jobStatus) && jobs.size() == 0)) {
+                mEconomyManagerInternal.unregisterAffordabilityChangeListener(
+                        userId, pkgName, mAffordabilityChangeListener, bill);
+                // Remove the cached value so we don't accidentally use it when the app
+                // schedules a new job.
+                final ArrayMap<ActionBill, Boolean> actionAffordability =
+                        mAffordabilityCache.get(userId, pkgName);
+                if (actionAffordability != null) {
+                    actionAffordability.remove(bill);
+                }
+            }
+        }
+    }
+
+    @NonNull
+    private ArraySet<ActionBill> getPossibleStartBills(JobStatus jobStatus) {
+        // TODO: factor in network cost when available
+        final ArraySet<ActionBill> bills = new ArraySet<>();
+        if (jobStatus.isRequestedExpeditedJob()) {
+            bills.add(BILL_JOB_START_EXPEDITED);
+        }
+        bills.add(BILL_JOB_START_DEFAULT);
+        return bills;
+    }
+
+    @GuardedBy("mLock")
+    private boolean canAffordBillLocked(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
+        if (!mIsEnabled) {
+            return true;
+        }
+        final int userId = jobStatus.getSourceUserId();
+        final String pkgName = jobStatus.getSourcePackageName();
+        ArrayMap<ActionBill, Boolean> actionAffordability =
+                mAffordabilityCache.get(userId, pkgName);
+        if (actionAffordability == null) {
+            actionAffordability = new ArrayMap<>();
+            mAffordabilityCache.add(userId, pkgName, actionAffordability);
+        }
+
+        if (actionAffordability.containsKey(bill)) {
+            return actionAffordability.get(bill);
+        }
+
+        final boolean canAfford = mEconomyManagerInternal.canPayFor(userId, pkgName, bill);
+        actionAffordability.put(bill, canAfford);
+        return canAfford;
+    }
+
+    @GuardedBy("mLock")
+    private boolean canAffordExpeditedBillLocked(@NonNull JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return true;
+        }
+        if (mService.isCurrentlyRunningLocked(jobStatus)) {
+            return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_EXPEDITED);
+        }
+
+        return canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED);
+    }
+
+    @GuardedBy("mLock")
+    private boolean hasEnoughWealthLocked(@NonNull JobStatus jobStatus) {
+        if (!mIsEnabled) {
+            return true;
+        }
+        if (mService.isCurrentlyRunningLocked(jobStatus)) {
+            if (jobStatus.isRequestedExpeditedJob()) {
+                return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_EXPEDITED)
+                        || canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_DEFAULT);
+            }
+            return canAffordBillLocked(jobStatus, BILL_JOB_RUNNING_DEFAULT);
+        }
+
+        if (jobStatus.isRequestedExpeditedJob()
+                && canAffordBillLocked(jobStatus, BILL_JOB_START_EXPEDITED)) {
+            return true;
+        }
+
+        return canAffordBillLocked(jobStatus, BILL_JOB_START_DEFAULT);
+    }
+
+    /**
+     * If the satisfaction changes, this will tell connectivity & background jobs controller to
+     * also re-evaluate their state.
+     */
+    private boolean setExpeditedTareApproved(@NonNull JobStatus jobStatus, long nowElapsed,
+            boolean isApproved) {
+        if (jobStatus.setExpeditedJobTareApproved(nowElapsed, isApproved)) {
+            mBackgroundJobsController.evaluateStateLocked(jobStatus);
+            mConnectivityController.evaluateStateLocked(jobStatus);
+            if (isApproved && jobStatus.isReady()) {
+                mStateChangedListener.onRunJobNow(jobStatus);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @NonNull
+    private String getBillName(@NonNull ActionBill bill) {
+        if (bill.equals(BILL_JOB_START_EXPEDITED)) {
+            return "EJ_START_BILL";
+        }
+        if (bill.equals(BILL_JOB_RUNNING_EXPEDITED)) {
+            return "EJ_RUNNING_BILL";
+        }
+        if (bill.equals(BILL_JOB_START_DEFAULT)) {
+            return "DEFAULT_START_BILL";
+        }
+        if (bill.equals(BILL_JOB_RUNNING_DEFAULT)) {
+            return "DEFAULT_RUNNING_BILL";
+        }
+        return "UNKNOWN_BILL (" + bill.toString() + ")";
+    }
+
+    @Override
+    public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+        pw.print("Is enabled: ");
+        pw.println(mIsEnabled);
+
+        pw.println("Affordability cache:");
+        pw.increaseIndent();
+        mAffordabilityCache.forEach((userId, pkgName, billMap) -> {
+            final int numBills = billMap.size();
+            if (numBills > 0) {
+                pw.print(userId);
+                pw.print(":");
+                pw.print(pkgName);
+                pw.println(":");
+
+                pw.increaseIndent();
+                for (int i = 0; i < numBills; ++i) {
+                    pw.print(getBillName(billMap.keyAt(i)));
+                    pw.print(": ");
+                    pw.println(billMap.valueAt(i));
+                }
+                pw.decreaseIndent();
+            }
+        });
+        pw.decreaseIndent();
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 7f09e71..829ad27 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -26,6 +26,8 @@
 import static com.android.server.tare.EconomicPolicy.TYPE_REWARD;
 import static com.android.server.tare.EconomicPolicy.eventToString;
 import static com.android.server.tare.EconomicPolicy.getEventType;
+import static com.android.server.tare.TareUtils.appToString;
+import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
 import static com.android.server.tare.TareUtils.narcToString;
 
 import android.annotation.NonNull;
@@ -183,7 +185,7 @@
                 mCurrentOngoingEvents.get(userId, pkgName);
         if (ongoingEvents != null) {
             final long nowElapsed = SystemClock.elapsedRealtime();
-            final long now = System.currentTimeMillis();
+            final long now = getCurrentTimeMillis();
             mTotalDeltaCalculator.reset(ledger, nowElapsed, now);
             ongoingEvents.forEach(mTotalDeltaCalculator);
             balance += mTotalDeltaCalculator.mTotal;
@@ -194,9 +196,13 @@
     @GuardedBy("mLock")
     void noteInstantaneousEventLocked(final int userId, @NonNull final String pkgName,
             final int eventId, @Nullable String tag) {
-        final long now = System.currentTimeMillis();
+        if (mIrs.isSystem(userId, pkgName)) {
+            // Events are free for the system. Don't bother recording them.
+            return;
+        }
+
+        final long now = getCurrentTimeMillis();
         final Ledger ledger = getLedgerLocked(userId, pkgName);
-        final boolean wasSolvent = getBalanceLocked(userId, pkgName) > 0;
 
         final int eventType = getEventType(eventId);
         switch (eventType) {
@@ -279,7 +285,7 @@
 
     @GuardedBy("mLock")
     void onDeviceStateChangedLocked() {
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
 
         mCurrentOngoingEvents.forEach((userId, pkgName, ongoingEvents) -> {
@@ -327,7 +333,7 @@
 
     @GuardedBy("mLock")
     void onAppStatesChangedLocked(final int userId, @NonNull ArraySet<String> pkgNames) {
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
 
         for (int i = 0; i < pkgNames.size(); ++i) {
@@ -400,24 +406,31 @@
         SparseArrayMap<String, OngoingEvent> ongoingEvents =
                 mCurrentOngoingEvents.get(userId, pkgName);
         if (ongoingEvents == null) {
-            Slog.wtf(TAG, "No ongoing transactions :/");
+            // This may occur if TARE goes from disabled to enabled while an event is already
+            // occurring.
+            Slog.w(TAG, "No ongoing transactions for <" + userId + ">" + pkgName);
             return;
         }
         final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
         if (ongoingEvent == null) {
-            Slog.wtf(TAG, "Nonexistent ongoing transaction "
+            // This may occur if TARE goes from disabled to enabled while an event is already
+            // occurring.
+            Slog.w(TAG, "Nonexistent ongoing transaction "
                     + eventToString(eventId) + (tag == null ? "" : ":" + tag)
                     + " for <" + userId + ">" + pkgName + " ended");
             return;
         }
         ongoingEvent.refCount--;
         if (ongoingEvent.refCount <= 0) {
-            final long startElapsed = ongoingEvent.startTimeElapsed;
-            final long startTime = now - (nowElapsed - startElapsed);
-            final long actualDelta = getActualDeltaLocked(ongoingEvent, ledger, nowElapsed, now);
-            recordTransactionLocked(userId, pkgName, ledger,
-                    new Ledger.Transaction(startTime, now, eventId, tag, actualDelta),
-                    notifyOnAffordabilityChange);
+            if (!mIrs.isSystem(userId, pkgName)) {
+                final long startElapsed = ongoingEvent.startTimeElapsed;
+                final long startTime = now - (nowElapsed - startElapsed);
+                final long actualDelta =
+                        getActualDeltaLocked(ongoingEvent, ledger, nowElapsed, now);
+                recordTransactionLocked(userId, pkgName, ledger,
+                        new Ledger.Transaction(startTime, now, eventId, tag, actualDelta),
+                        notifyOnAffordabilityChange);
+            }
             ongoingEvents.delete(eventId, tag);
         }
         if (updateBalanceCheck) {
@@ -443,6 +456,15 @@
     private void recordTransactionLocked(final int userId, @NonNull final String pkgName,
             @NonNull Ledger ledger, @NonNull Ledger.Transaction transaction,
             final boolean notifyOnAffordabilityChange) {
+        if (transaction.delta == 0) {
+            // Skip recording transactions with a delta of 0 to save on space.
+            return;
+        }
+        if (mIrs.isSystem(userId, pkgName)) {
+            Slog.wtfStack(TAG,
+                    "Tried to adjust system balance for " + appToString(userId, pkgName));
+            return;
+        }
         final long maxCirculationAllowed = mIrs.getMaxCirculationLocked();
         final long newArcsInCirculation = mCurrentNarcsInCirculation + transaction.delta;
         if (transaction.delta > 0 && newArcsInCirculation > maxCirculationAllowed) {
@@ -474,7 +496,7 @@
             // The earliest transaction won't change until we clean up the ledger, so no point
             // continuing to reschedule an existing cleanup.
             final long cleanupAlarmElapsed = SystemClock.elapsedRealtime() + MAX_TRANSACTION_AGE_MS
-                    - (System.currentTimeMillis() - ledger.getEarliestTransaction().endTimeMs);
+                    - (getCurrentTimeMillis() - ledger.getEarliestTransaction().endTimeMs);
             mLedgerCleanupAlarmListener.addAlarmLocked(userId, pkgName, cleanupAlarmElapsed);
         }
         // TODO: save changes to disk in a background thread
@@ -506,7 +528,7 @@
     @GuardedBy("mLock")
     void reclaimUnusedAssetsLocked(double percentage) {
         final List<PackageInfo> pkgs = mIrs.getInstalledPackages();
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         for (int i = 0; i < pkgs.size(); ++i) {
             final int userId = UserHandle.getUserId(pkgs.get(i).applicationInfo.uid);
             final String pkgName = pkgs.get(i).packageName;
@@ -540,11 +562,15 @@
     @GuardedBy("mLock")
     void distributeBasicIncomeLocked(int batteryLevel) {
         List<PackageInfo> pkgs = mIrs.getInstalledPackages();
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         for (int i = 0; i < pkgs.size(); ++i) {
             final PackageInfo pkgInfo = pkgs.get(i);
             final int userId = UserHandle.getUserId(pkgInfo.applicationInfo.uid);
             final String pkgName = pkgInfo.packageName;
+            if (mIrs.isSystem(userId, pkgName)) {
+                // No point allocating ARCs to the system. It can do whatever it wants.
+                continue;
+            }
             Ledger ledger = getLedgerLocked(userId, pkgName);
             final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
             final double perc = batteryLevel / 100d;
@@ -575,12 +601,16 @@
         List<PackageInfo> pkgs = packageManager.getInstalledPackagesAsUser(0, userId);
         final long maxBirthright =
                 mIrs.getMaxCirculationLocked() / mIrs.getInstalledPackages().size();
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
 
         for (int i = 0; i < pkgs.size(); ++i) {
             final PackageInfo packageInfo = pkgs.get(i);
             final String pkgName = packageInfo.packageName;
             final Ledger ledger = getLedgerLocked(userId, pkgName);
+            if (mIrs.isSystem(userId, pkgName)) {
+                // No point allocating ARCs to the system. It can do whatever it wants.
+                continue;
+            }
             if (ledger.getCurrentBalance() > 0) {
                 // App already got credits somehow. Move along.
                 Slog.wtf(TAG, "App " + pkgName + " had credits before economy was set up");
@@ -606,7 +636,7 @@
         List<PackageInfo> pkgs = mIrs.getInstalledPackages();
         final int numPackages = pkgs.size();
         final long maxBirthright = mIrs.getMaxCirculationLocked() / numPackages;
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
 
         recordTransactionLocked(userId, pkgName, ledger,
                 new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null,
@@ -768,6 +798,15 @@
                 SystemClock.elapsedRealtime() + timeToThresholdMs);
     }
 
+    @GuardedBy("mLock")
+    void tearDownLocked() {
+        mLedgers.clear();
+        mCurrentNarcsInCirculation = 0;
+        mCurrentOngoingEvents.clear();
+        mBalanceThresholdAlarmListener.dropAllAlarmsLocked();
+        mLedgerCleanupAlarmListener.dropAllAlarmsLocked();
+    }
+
     @VisibleForTesting
     static class OngoingEvent {
         public final long startTimeElapsed;
@@ -987,6 +1026,12 @@
         }
 
         @GuardedBy("mLock")
+        void dropAllAlarmsLocked() {
+            mAlarmQueue.clear();
+            setNextAlarmLocked(0);
+        }
+
+        @GuardedBy("mLock")
         protected abstract void processExpiredAlarmLocked(int userId, @NonNull String packageName);
 
         @Override
@@ -1069,6 +1114,13 @@
         final ActionAffordabilityNote note =
                 new ActionAffordabilityNote(bill, listener, mCompleteEconomicPolicy);
         if (actionAffordabilityNotes.add(note)) {
+            if (!mIrs.isEnabled()) {
+                // When TARE isn't enabled, we always say something is affordable. We also don't
+                // want to silently drop affordability change listeners in case TARE becomes enabled
+                // because then clients will be in an ambiguous state.
+                note.setNewAffordability(true);
+                return;
+            }
             note.recalculateModifiedPrice(mCompleteEconomicPolicy, userId, pkgName);
             note.setNewAffordability(
                     getBalanceLocked(userId, pkgName) >= note.getCachedModifiedPrice());
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
index a627de6..712e13e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
@@ -40,7 +40,16 @@
         super();
         mIrs = irs;
         mChargingTracker = new ChargingTracker();
-        mChargingTracker.startTracking(irs.getContext());
+    }
+
+    @Override
+    public void setup() {
+        mChargingTracker.startTracking(mIrs.getContext());
+    }
+
+    @Override
+    public void tearDown() {
+        mChargingTracker.stopTracking(mIrs.getContext());
     }
 
     @Override
@@ -84,6 +93,10 @@
             mCharging = batteryManager.isCharging();
         }
 
+        public void stopTracking(@NonNull Context context) {
+            context.unregisterReceiver(this);
+        }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
index 20b9c70..37b0aa8 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
@@ -40,7 +40,16 @@
         mIrs = irs;
         mPowerManager = irs.getContext().getSystemService(PowerManager.class);
         mDeviceIdleTracker = new DeviceIdleTracker();
-        mDeviceIdleTracker.startTracking(irs.getContext());
+    }
+
+    @Override
+    public void setup() {
+        mDeviceIdleTracker.startTracking(mIrs.getContext());
+    }
+
+    @Override
+    public void tearDown() {
+        mDeviceIdleTracker.stopTracking(mIrs.getContext());
     }
 
     @Override
@@ -81,6 +90,10 @@
             mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
         }
 
+        void stopTracking(@NonNull Context context) {
+            context.unregisterReceiver(this);
+        }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index f08dd24..fa14d10 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -157,11 +157,21 @@
     }
 
     @CallSuper
-    void onSystemServicesReady() {
+    void setup() {
         for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
             final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
             if (modifier != null) {
-                modifier.onSystemServicesReady();
+                modifier.setup();
+            }
+        }
+    }
+
+    @CallSuper
+    void tearDown() {
+        for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
+            final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
+            if (modifier != null) {
+                modifier.tearDown();
             }
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
index 831c05f..29aa946 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
@@ -124,6 +124,11 @@
      */
     boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
 
+    /**
+     * Returns the maximum duration (in milliseconds) that the specified app can afford the bill,
+     * based on current prices.
+     */
+    long getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
 
     /**
      * Register an {@link AffordabilityChangeListener} to track when an app's ability to afford the
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 0bbb802..a2ba75c 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -19,16 +19,21 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
+import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.tare.IEconomyManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.BatteryManagerInternal;
 import android.os.Binder;
@@ -38,10 +43,12 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArrayMap;
 import android.util.SparseSetArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -78,9 +85,11 @@
     private final Handler mHandler;
     private final BatteryManagerInternal mBatteryManagerInternal;
     private final PackageManager mPackageManager;
+    private final PackageManagerInternal mPackageManagerInternal;
 
     private final Agent mAgent;
     private final CompleteEconomicPolicy mCompleteEconomicPolicy;
+    private final ConfigObserver mConfigObserver;
     private final EconomyManagerStub mEconomyManagerStub;
 
     @NonNull
@@ -91,8 +100,12 @@
     @GuardedBy("mLock")
     private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
 
-    @GuardedBy("mLock")
-    private boolean mIsSetup;
+    /** Cached mapping of userId+package to their UIDs (for all users) */
+    @GuardedBy("mPackageToUidCache")
+    private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
+
+    private volatile boolean mIsEnabled;
+    private volatile int mBootPhase;
     // In the range [0,100] to represent 0% to 100% battery.
     @GuardedBy("mLock")
     private int mCurrentBatteryLevel;
@@ -100,7 +113,6 @@
     @GuardedBy("mLock")
     private long mLastUnusedReclamationTime;
 
-    @SuppressWarnings("FieldCanBeLocal")
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Nullable
         private String getPackageName(Intent intent) {
@@ -155,7 +167,7 @@
                 public void onAlarm() {
                     synchronized (mLock) {
                         mAgent.reclaimUnusedAssetsLocked(DEFAULT_UNUSED_RECLAMATION_PERCENTAGE);
-                        mLastUnusedReclamationTime = System.currentTimeMillis();
+                        mLastUnusedReclamationTime = getCurrentTimeMillis();
                         scheduleUnusedWealthReclamationLocked();
                     }
                 }
@@ -181,22 +193,12 @@
         mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
         mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
         mPackageManager = context.getPackageManager();
+        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mEconomyManagerStub = new EconomyManagerStub();
         mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
         mAgent = new Agent(this, mCompleteEconomicPolicy);
 
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
-        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
-        final IntentFilter pkgFilter = new IntentFilter();
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
-        pkgFilter.addDataScheme("package");
-        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
-        final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_ADDED);
-        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+        mConfigObserver = new ConfigObserver(mHandler, context);
 
         publishLocalService(EconomyManagerInternal.class, new LocalService());
     }
@@ -208,19 +210,11 @@
 
     @Override
     public void onBootPhase(int phase) {
+        mBootPhase = phase;
+
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
-            synchronized (mLock) {
-                mCurrentBatteryLevel = getCurrentBatteryLevel();
-                // TODO: base on if we have anything persisted
-                final boolean isFirstSetup = true;
-                if (isFirstSetup) {
-                    mHandler.post(this::setupEconomy);
-                } else {
-                    mIsSetup = true;
-                }
-                scheduleUnusedWealthReclamationLocked();
-                mCompleteEconomicPolicy.onSystemServicesReady();
-            }
+            mConfigObserver.start();
+            setupEverything();
         }
     }
 
@@ -247,6 +241,28 @@
                 / 100;
     }
 
+    int getUid(final int userId, @NonNull final String pkgName) {
+        synchronized (mPackageToUidCache) {
+            Integer uid = mPackageToUidCache.get(userId, pkgName);
+            if (uid == null) {
+                uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
+                mPackageToUidCache.add(userId, pkgName, uid);
+            }
+            return uid;
+        }
+    }
+
+    boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    boolean isSystem(final int userId, @NonNull String pkgName) {
+        if ("android".equals(pkgName)) {
+            return true;
+        }
+        return UserHandle.isCore(getUid(userId, pkgName));
+    }
+
     void onBatteryLevelChanged() {
         synchronized (mLock) {
             final int newBatteryLevel = getCurrentBatteryLevel();
@@ -272,6 +288,9 @@
             Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName);
             return;
         }
+        synchronized (mPackageToUidCache) {
+            mPackageToUidCache.add(userId, pkgName, uid);
+        }
         synchronized (mLock) {
             mPkgCache.add(packageInfo);
             mUidToPackageCache.add(uid, pkgName);
@@ -288,6 +307,9 @@
 
     void onPackageRemoved(final int uid, @NonNull final String pkgName) {
         final int userId = UserHandle.getUserId(uid);
+        synchronized (mPackageToUidCache) {
+            mPackageToUidCache.delete(userId, pkgName);
+        }
         synchronized (mLock) {
             mUidToPackageCache.remove(uid, pkgName);
             for (int i = 0; i < mPkgCache.size(); ++i) {
@@ -353,7 +375,7 @@
 
     @GuardedBy("mLock")
     private void scheduleUnusedWealthReclamationLocked() {
-        final long now = System.currentTimeMillis();
+        final long now = getCurrentTimeMillis();
         final long nextReclamationTime =
                 Math.max(mLastUnusedReclamationTime + UNUSED_RECLAMATION_PERIOD_MS, now + 30_000);
         mHandler.post(() -> {
@@ -396,11 +418,70 @@
         mPkgCache = mPackageManager.getInstalledPackages(0);
     }
 
-    private void setupEconomy() {
+    private void registerReceivers() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
+        getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
+        final IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+        pkgFilter.addDataScheme("package");
+        getContext()
+                .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
+
+        final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_ADDED);
+        getContext()
+                .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+    }
+
+    /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
+    private void setupHeavyWork() {
         synchronized (mLock) {
             loadInstalledPackageListLocked();
-            mAgent.grantBirthrightsLocked();
-            mIsSetup = true;
+            // TODO: base on if we have anything persisted
+            final boolean isFirstSetup = true;
+            if (isFirstSetup) {
+                mAgent.grantBirthrightsLocked();
+            }
+        }
+    }
+
+    private void setupEverything() {
+        if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || !mIsEnabled) {
+            return;
+        }
+        synchronized (mLock) {
+            registerReceivers();
+            mCurrentBatteryLevel = getCurrentBatteryLevel();
+            mHandler.post(this::setupHeavyWork);
+            scheduleUnusedWealthReclamationLocked();
+            mCompleteEconomicPolicy.setup();
+        }
+    }
+
+    private void tearDownEverything() {
+        if (mIsEnabled) {
+            return;
+        }
+        synchronized (mLock) {
+            mAgent.tearDownLocked();
+            mCompleteEconomicPolicy.tearDown();
+            mHandler.post(() -> {
+                // Never call out to AlarmManager with the lock held. This sits below AM.
+                AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
+                if (alarmManager != null) {
+                    alarmManager.cancel(mUnusedWealthReclamationListener);
+                }
+            });
+            mPkgCache.clear();
+            mUidToPackageCache.clear();
+            getContext().unregisterReceiver(mBroadcastReceiver);
+        }
+        synchronized (mPackageToUidCache) {
+            mPackageToUidCache.clear();
         }
     }
 
@@ -469,9 +550,22 @@
     }
 
     private final class LocalService implements EconomyManagerInternal {
+        /**
+         * Use an extremely large value to indicate that an app can pay for a bill indefinitely.
+         * The value set here should be large/long enough that there's no reasonable expectation
+         * of a device operating uninterrupted (or in the exact same state) for that period of time.
+         * We intentionally don't use Long.MAX_VALUE to avoid potential overflow if a client
+         * doesn't check the value and just immediately adds it to the current time.
+         */
+        private static final long FOREVER_MS = 27 * 365 * 24 * HOUR_IN_MILLIS;
+
         @Override
         public void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
                 @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
+            if (isSystem(userId, pkgName)) {
+                // The system's affordability never changes.
+                return;
+            }
             synchronized (mLock) {
                 mAgent.registerAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
             }
@@ -480,6 +574,10 @@
         @Override
         public void unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName,
                 @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
+            if (isSystem(userId, pkgName)) {
+                // The system's affordability never changes.
+                return;
+            }
             synchronized (mLock) {
                 mAgent.unregisterAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
             }
@@ -487,6 +585,14 @@
 
         @Override
         public boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill) {
+            if (!mIsEnabled) {
+                return true;
+            }
+            if (isSystem(userId, pkgName)) {
+                // The government, I mean the system, can create ARCs as it needs to in order to
+                // operate.
+                return true;
+            }
             // TODO: take temp-allowlist into consideration
             long requiredBalance = 0;
             final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
@@ -504,8 +610,37 @@
         }
 
         @Override
+        public long getMaxDurationMs(int userId, @NonNull String pkgName,
+                @NonNull ActionBill bill) {
+            if (!mIsEnabled) {
+                return FOREVER_MS;
+            }
+            if (isSystem(userId, pkgName)) {
+                return FOREVER_MS;
+            }
+            long totalCostPerSecond = 0;
+            final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
+                    bill.getAnticipatedActions();
+            for (int i = 0; i < projectedActions.size(); ++i) {
+                AnticipatedAction action = projectedActions.get(i);
+                final long cost =
+                        mCompleteEconomicPolicy.getCostOfAction(action.actionId, userId, pkgName);
+                totalCostPerSecond += cost;
+            }
+            if (totalCostPerSecond == 0) {
+                return FOREVER_MS;
+            }
+            synchronized (mLock) {
+                return mAgent.getBalanceLocked(userId, pkgName) * 1000 / totalCostPerSecond;
+            }
+        }
+
+        @Override
         public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
                 @Nullable String tag) {
+            if (!mIsEnabled) {
+                return;
+            }
             synchronized (mLock) {
                 mAgent.noteInstantaneousEventLocked(userId, pkgName, eventId, tag);
             }
@@ -514,6 +649,9 @@
         @Override
         public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
                 @Nullable String tag) {
+            if (!mIsEnabled) {
+                return;
+            }
             synchronized (mLock) {
                 final long nowElapsed = SystemClock.elapsedRealtime();
                 mAgent.noteOngoingEventLocked(userId, pkgName, eventId, tag, nowElapsed);
@@ -523,14 +661,50 @@
         @Override
         public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
                 @Nullable String tag) {
+            if (!mIsEnabled) {
+                return;
+            }
             final long nowElapsed = SystemClock.elapsedRealtime();
-            final long now = System.currentTimeMillis();
+            final long now = getCurrentTimeMillis();
             synchronized (mLock) {
                 mAgent.stopOngoingActionLocked(userId, pkgName, eventId, tag, nowElapsed, now);
             }
         }
     }
 
+    private class ConfigObserver extends ContentObserver {
+        private final ContentResolver mContentResolver;
+
+        ConfigObserver(Handler handler, Context context) {
+            super(handler);
+            mContentResolver = context.getContentResolver();
+        }
+
+        public void start() {
+            mContentResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
+            updateConfig();
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            updateConfig();
+        }
+
+        private void updateConfig() {
+            final boolean isTareEnabled = Settings.Global.getInt(mContentResolver,
+                    Settings.Global.ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE) == 1;
+            if (mIsEnabled != isTareEnabled) {
+                mIsEnabled = isTareEnabled;
+                if (mIsEnabled) {
+                    setupEverything();
+                } else {
+                    tearDownEverything();
+                }
+            }
+        }
+    }
+
     private static void dumpHelp(PrintWriter pw) {
         pw.println("Resource Economy (economy) dump options:");
         pw.println("  [-h|--help] [package] ...");
@@ -540,6 +714,9 @@
 
     private void dumpInternal(final IndentingPrintWriter pw) {
         synchronized (mLock) {
+            pw.print("Is enabled: ");
+            pw.println(mIsEnabled);
+
             pw.print("Current battery level: ");
             pw.println(mCurrentBatteryLevel);
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index cce75f7..ff008a2 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -17,6 +17,7 @@
 package com.android.server.tare;
 
 import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
+import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
 import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
 import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
 import static com.android.server.tare.TareUtils.arcToNarc;
@@ -44,6 +45,7 @@
 
     private static final int[] COST_MODIFIERS = new int[]{
             COST_MODIFIER_CHARGING,
+            COST_MODIFIER_DEVICE_IDLE,
             COST_MODIFIER_POWER_SAVE_MODE,
             COST_MODIFIER_PROCESS_STATE
     };
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
index ae1bf26..76543d7 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
@@ -19,6 +19,7 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 
 import static com.android.server.tare.TareUtils.dumpTime;
+import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
 import static com.android.server.tare.TareUtils.narcToString;
 
 import android.annotation.NonNull;
@@ -109,8 +110,8 @@
 
     /** Deletes transactions that are older than {@code minAgeMs}. */
     void removeOldTransactions(long minAgeMs) {
-        final long cutoff = System.currentTimeMillis() - minAgeMs;
-        while (mTransactions.get(0).endTimeMs <= cutoff) {
+        final long cutoff = getCurrentTimeMillis() - minAgeMs;
+        while (mTransactions.size() > 0 && mTransactions.get(0).endTimeMs <= cutoff) {
             mTransactions.remove(0);
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
index 6b89b79..311b6cb 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
@@ -60,7 +60,10 @@
         return price;
     }
 
-    void onSystemServicesReady() {
+    void setup() {
+    }
+
+    void tearDown() {
     }
 
     abstract void dump(IndentingPrintWriter pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
index 2ee6459..67a3dc6 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.IUidObserver;
-import android.content.pm.PackageManagerInternal;
 import android.os.RemoteException;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -28,7 +27,6 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -56,7 +54,6 @@
 
     private final Object mLock = new Object();
     private final InternalResourceService mIrs;
-    private final PackageManagerInternal mPackageManagerInternal;
 
     /** Cached mapping of userId+package to their UIDs (for all users) */
     private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
@@ -105,12 +102,11 @@
     ProcessStateModifier(@NonNull InternalResourceService irs) {
         super();
         mIrs = irs;
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
     }
 
     @Override
     @GuardedBy("mLock")
-    void onSystemServicesReady() {
+    void setup() {
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
@@ -120,6 +116,18 @@
         }
     }
 
+    @Override
+    @GuardedBy("mLock")
+    void tearDown() {
+        try {
+            ActivityManager.getService().unregisterUidObserver(mUidObserver);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+        mPackageToUidCache.clear();
+        mUidProcStateBucketCache.clear();
+    }
+
     /**
      * Get the final modified price based on an app's process state.
      *
@@ -131,7 +139,7 @@
         final int procState;
         synchronized (mLock) {
             procState = mUidProcStateBucketCache.get(
-                    getUidLocked(userId, pkgName), PROC_STATE_BUCKET_NONE);
+                    mIrs.getUid(userId, pkgName), PROC_STATE_BUCKET_NONE);
         }
         switch (procState) {
             case PROC_STATE_BUCKET_TOP:
@@ -154,15 +162,6 @@
         pw.println(mUidProcStateBucketCache);
     }
 
-    @GuardedBy("mLock")
-    private int getUidLocked(final int userId, @NonNull final String pkgName) {
-        if (!mPackageToUidCache.contains(userId, pkgName)) {
-            mPackageToUidCache.add(userId, pkgName,
-                    mPackageManagerInternal.getPackageUid(pkgName, 0, userId));
-        }
-        return mPackageToUidCache.get(userId, pkgName);
-    }
-
     @ProcStateBucket
     private int getProcStateBucket(int procState) {
         if (procState <= ActivityManager.PROCESS_STATE_TOP) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
index 2d72f56..1e047aa 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
@@ -20,7 +20,10 @@
 import android.annotation.SuppressLint;
 import android.util.IndentingPrintWriter;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.text.SimpleDateFormat;
+import java.time.Clock;
 
 class TareUtils {
     private static final long NARC_IN_ARC = 1_000_000_000L;
@@ -29,6 +32,9 @@
     private static final SimpleDateFormat sDumpDateFormat =
             new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
 
+    @VisibleForTesting
+    static Clock sSystemClock = Clock.systemUTC();
+
     static long arcToNarc(int arcs) {
         return arcs * NARC_IN_ARC;
     }
@@ -37,6 +43,10 @@
         pw.print(sDumpDateFormat.format(time));
     }
 
+    static long getCurrentTimeMillis() {
+        return sSystemClock.millis();
+    }
+
     static int narcToArc(long narcs) {
         return (int) (narcs / NARC_IN_ARC);
     }
@@ -59,4 +69,10 @@
         sb.append(" ARCs");
         return sb.toString();
     }
+
+    /** Returns a standardized format for printing userId+pkgName combinations. */
+    @NonNull
+    static String appToString(int userId, String pkgName) {
+        return "<" + userId + ">" + pkgName;
+    }
 }
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index b2b66c2..3534624 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -71,7 +71,7 @@
         "libui",
         "libjnigraphics",
         "libEGL",
-        "libGLESv1_CM",
+        "libGLESv2",
         "libgui",
     ],
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3109c5c..6e27aff 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -52,9 +52,8 @@
 #include <gui/DisplayEventReceiver.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 #include <EGL/eglext.h>
 
 #include "BootAnimation.h"
@@ -108,6 +107,56 @@
 static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
 static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
 static constexpr size_t TEXT_POS_LEN_MAX = 16;
+static const char U_TEXTURE[] = "uTexture";
+static const char U_FADE[] = "uFade";
+static const char U_CROP_AREA[] = "uCropArea";
+static const char A_UV[] = "aUv";
+static const char A_POSITION[] = "aPosition";
+static const char VERTEX_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    attribute vec4 aPosition;
+    attribute highp vec2 aUv;
+    varying highp vec2 vUv;
+    void main() {
+        gl_Position = aPosition;
+        vUv = aUv;
+    })";
+static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    uniform sampler2D uTexture;
+    uniform float uFade;
+    varying highp vec2 vUv;
+    void main() {
+        vec4 color = texture2D(uTexture, vUv);
+        gl_FragColor = vec4(color.x, color.y, color.z, 1.0 - uFade);
+    })";
+static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
+    precision mediump float;
+    uniform sampler2D uTexture;
+    uniform vec4 uCropArea;
+    varying highp vec2 vUv;
+    void main() {
+        vec2 uv = vec2(mix(uCropArea.x, uCropArea.z, vUv.x),
+                       mix(uCropArea.y, uCropArea.w, vUv.y));
+        gl_FragColor = texture2D(uTexture, uv);
+    })";
+
+static GLfloat quadPositions[] = {
+    -0.5f, -0.5f,
+    +0.5f, -0.5f,
+    +0.5f, +0.5f,
+    +0.5f, +0.5f,
+    -0.5f, +0.5f,
+    -0.5f, -0.5f
+};
+static GLfloat quadUVs[] = {
+    0.0f, 1.0f,
+    1.0f, 1.0f,
+    1.0f, 0.0f,
+    1.0f, 0.0f,
+    0.0f, 0.0f,
+    0.0f, 1.0f
+};
 
 // ---------------------------------------------------------------------------
 
@@ -209,7 +258,6 @@
     const int w = bitmapInfo.width;
     const int h = bitmapInfo.height;
 
-    GLint crop[4] = { 0, h, w, -h };
     texture->w = w;
     texture->h = h;
 
@@ -237,11 +285,10 @@
             break;
     }
 
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     return NO_ERROR;
 }
@@ -263,7 +310,6 @@
     const int w = bitmapInfo.width;
     const int h = bitmapInfo.height;
 
-    GLint crop[4] = { 0, h, w, -h };
     int tw = 1 << (31 - __builtin_clz(w));
     int th = 1 << (31 - __builtin_clz(h));
     if (tw < w) tw <<= 1;
@@ -297,7 +343,10 @@
             break;
     }
 
-    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     *width = w;
     *height = h;
@@ -470,7 +519,9 @@
     eglInitialize(display, nullptr, nullptr);
     EGLConfig config = getEglConfig(display);
     EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
-    EGLContext context = eglCreateContext(display, config, nullptr, nullptr);
+    // Initialize egl context with client version number 2.0.
+    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
     EGLint w, h;
     eglQuerySurface(display, surface, EGL_WIDTH, &w);
     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -503,11 +554,6 @@
 void BootAnimation::projectSceneToWindow() {
     glViewport(0, 0, mWidth, mHeight);
     glScissor(0, 0, mWidth, mHeight);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
 }
 
 void BootAnimation::resizeSurface(int newWidth, int newHeight) {
@@ -600,8 +646,68 @@
     }
 }
 
+GLuint compileShader(GLenum shaderType, const GLchar *source) {
+    GLuint shader = glCreateShader(shaderType);
+    glShaderSource(shader, 1, &source, 0);
+    glCompileShader(shader);
+    GLint isCompiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+    if (isCompiled == GL_FALSE) {
+        SLOGE("Compile shader failed. Shader type: %d", shaderType);
+        return 0;
+    }
+    return shader;
+}
+
+GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
+    GLuint program = glCreateProgram();
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, fragmentShader);
+    glLinkProgram(program);
+    GLint isLinked = 0;
+    glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
+    if (isLinked == GL_FALSE) {
+        SLOGE("Linking shader failed. Shader handles: vert %d, frag %d",
+            vertexShader, fragmentShader);
+        return 0;
+    }
+    return program;
+}
+
+void BootAnimation::initShaders() {
+    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
+    GLuint imageFragmentShader =
+        compileShader(GL_FRAGMENT_SHADER, (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
+    GLuint textFragmentShader =
+        compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
+
+    // Initialize image shader.
+    mImageShader = linkShader(vertexShader, imageFragmentShader);
+    GLint positionLocation = glGetAttribLocation(mImageShader, A_POSITION);
+    GLint uvLocation = glGetAttribLocation(mImageShader, A_UV);
+    mImageTextureLocation = glGetUniformLocation(mImageShader, U_TEXTURE);
+    mImageFadeLocation = glGetUniformLocation(mImageShader, U_FADE);
+    glEnableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 2,  GL_FLOAT, GL_FALSE, 0, quadPositions);
+    glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+    glEnableVertexAttribArray(uvLocation);
+
+    // Initialize text shader.
+    mTextShader = linkShader(vertexShader, textFragmentShader);
+    positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
+    uvLocation = glGetAttribLocation(mTextShader, A_UV);
+    mTextTextureLocation = glGetUniformLocation(mTextShader, U_TEXTURE);
+    mTextCropAreaLocation = glGetUniformLocation(mTextShader, U_CROP_AREA);
+    glEnableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 2,  GL_FLOAT, GL_FALSE, 0, quadPositions);
+    glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
+    glEnableVertexAttribArray(uvLocation);
+}
+
 bool BootAnimation::threadLoop() {
     bool result;
+    initShaders();
+
     // We have no bootanimation file, so we use the stock android logo
     // animation.
     if (mZipFileName.isEmpty()) {
@@ -623,6 +729,8 @@
 }
 
 bool BootAnimation::android() {
+    glActiveTexture(GL_TEXTURE0);
+
     SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
             elapsedRealtime());
     initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
@@ -631,19 +739,14 @@
     mCallbacks->init({});
 
     // clear screen
-    glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
     glClearColor(0,0,0,1);
     glClear(GL_COLOR_BUFFER_BIT);
     eglSwapBuffers(mDisplay, mSurface);
 
-    glEnable(GL_TEXTURE_2D);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-
     // Blend state
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
     const nsecs_t startTime = systemTime();
     do {
@@ -666,12 +769,12 @@
         glEnable(GL_SCISSOR_TEST);
         glDisable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
-        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
-        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
+        drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);
+        drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);
 
         glEnable(GL_BLEND);
         glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
-        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
+        drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
 
         EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
         if (res == EGL_FALSE)
@@ -798,10 +901,10 @@
 
         status = initTexture(font->map, &font->texture.w, &font->texture.h);
 
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     } else if (fallback != nullptr) {
         status = initTexture(&font->texture, mAssets, fallback);
     } else {
@@ -816,40 +919,11 @@
     return status;
 }
 
-void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
-                              const int frameHeight, const Animation::Part& part,
-                              const int fadedFramesCount) {
-    glEnable(GL_BLEND);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glDisable(GL_TEXTURE_2D);
-    // avoid creating a hole due to mixing result alpha with GL_REPLACE texture
-    glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
-
-    const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount;
-    glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
-
-    const float frameStartX = static_cast<float>(frameLeft);
-    const float frameStartY = static_cast<float>(frameBottom);
-    const float frameEndX = frameStartX + frameWidth;
-    const float frameEndY = frameStartY + frameHeight;
-    const GLfloat frameRect[] = {
-        frameStartX, frameStartY,
-        frameEndX,   frameStartY,
-        frameEndX,   frameEndY,
-        frameStartX, frameEndY
-    };
-    glVertexPointer(2, GL_FLOAT, 0, frameRect);
-    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glEnable(GL_TEXTURE_2D);
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisable(GL_BLEND);
-}
-
 void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
     glEnable(GL_BLEND);  // Allow us to draw on top of the animation
     glBindTexture(GL_TEXTURE_2D, font.texture.name);
+    glUseProgram(mTextShader);
+    glUniform1i(mTextTextureLocation, 0);
 
     const int len = strlen(str);
     const int strWidth = font.char_width * len;
@@ -865,8 +939,6 @@
         *y = mHeight + *y - font.char_height;
     }
 
-    int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
-
     for (int i = 0; i < len; i++) {
         char c = str[i];
 
@@ -878,13 +950,13 @@
         const int charPos = (c - FONT_BEGIN_CHAR);  // Position in the list of valid characters
         const int row = charPos / FONT_NUM_COLS;
         const int col = charPos % FONT_NUM_COLS;
-        cropRect[0] = col * font.char_width;  // Left of column
-        cropRect[1] = row * font.char_height * 2; // Top of row
-        // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
-        cropRect[1] += bold ? 2 * font.char_height : font.char_height;
-        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
-
-        glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
+        // Bold fonts are expected in the second half of each row.
+        float v0 = (row + (bold ? 0.5f : 0.0f)) / FONT_NUM_ROWS;
+        float u0 = ((float)col) / FONT_NUM_COLS;
+        float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2;
+        float u1 = u0 + 1.0f / FONT_NUM_COLS;
+        glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1);
+        drawTexturedQuad(*x, *y, font.char_width, font.char_height);
 
         *x += font.char_width;
     }
@@ -1166,19 +1238,16 @@
 
     // Blend required to draw time on top of animation frames.
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
     glDisable(GL_BLEND);
 
-    glBindTexture(GL_TEXTURE_2D, 0);
     glEnable(GL_TEXTURE_2D);
-    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     bool clockFontInitialized = false;
     if (mClockEnabled) {
         clockFontInitialized =
@@ -1218,6 +1287,34 @@
         (lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
 }
 
+// Linear mapping from range <a1, a2> to range <b1, b2>
+float mapLinear(float x, float a1, float a2, float b1, float b2) {
+    return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
+}
+
+void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+    // Map coordinates from screen space to world space.
+    float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
+    float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
+    float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1);
+    float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1);
+    // Update quad vertex positions.
+    quadPositions[0] = x0;
+    quadPositions[1] = y0;
+    quadPositions[2] = x1;
+    quadPositions[3] = y0;
+    quadPositions[4] = x1;
+    quadPositions[5] = y1;
+    quadPositions[6] = x1;
+    quadPositions[7] = y1;
+    quadPositions[8] = x0;
+    quadPositions[9] = y1;
+    quadPositions[10] = x0;
+    quadPositions[11] = y0;
+    glDrawArrays(GL_TRIANGLES, 0,
+        sizeof(quadPositions) / sizeof(quadPositions[0]) / 2);
+}
+
 bool BootAnimation::playAnimation(const Animation& animation) {
     const size_t pcount = animation.parts.size();
     nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -1230,7 +1327,6 @@
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
         const size_t fcount = part.frames.size();
-        glBindTexture(GL_TEXTURE_2D, 0);
 
         // Handle animation package
         if (part.animation != nullptr) {
@@ -1272,12 +1368,8 @@
                 if (r > 0) {
                     glBindTexture(GL_TEXTURE_2D, frame.tid);
                 } else {
-                    if (part.count != 1) {
-                        glGenTextures(1, &frame.tid);
-                        glBindTexture(GL_TEXTURE_2D, frame.tid);
-                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-                    }
+                    glGenTextures(1, &frame.tid);
+                    glBindTexture(GL_TEXTURE_2D, frame.tid);
                     int w, h;
                     initTexture(frame.map, &w, &h);
                 }
@@ -1300,16 +1392,21 @@
                 // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
                 // which is equivalent to mHeight - (yc + frame.trimHeight)
                 const int frameDrawY = mHeight - (yc + frame.trimHeight);
-                glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
 
+                float fade = 0;
                 // if the part hasn't been stopped yet then continue fading if necessary
                 if (exitPending() && part.hasFadingPhase()) {
-                    fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
-                              ++fadedFramesCount);
+                    fade = static_cast<float>(++fadedFramesCount) / part.framesToFadeCount;
                     if (fadedFramesCount >= part.framesToFadeCount) {
                         fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
                     }
                 }
+                glUseProgram(mImageShader);
+                glUniform1i(mImageTextureLocation, 0);
+                glUniform1f(mImageFadeLocation, fade);
+                glEnable(GL_BLEND);
+                drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
+                glDisable(GL_BLEND);
 
                 if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
                     drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f8a31c6..7b616d9 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -31,7 +31,7 @@
 #include <binder/IBinder.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>
+#include <GLES2/gl2.h>
 
 namespace android {
 
@@ -166,6 +166,7 @@
     status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
     status_t initTexture(FileMap* map, int* width, int* height);
     status_t initFont(Font* font, const char* fallback);
+    void initShaders();
     bool android();
     bool movie();
     void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
@@ -173,6 +174,7 @@
     void drawProgress(int percent, const Font& font, const int xPos, const int yPos);
     void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
                    const Animation::Part& part, int fadedFramesCount);
+    void drawTexturedQuad(float xStart, float yStart, float width, float height);
     bool validClock(const Animation::Part& part);
     Animation* loadAnimation(const String8&);
     bool playAnimation(const Animation&);
@@ -218,6 +220,12 @@
     sp<TimeCheckThread> mTimeCheckThread = nullptr;
     sp<Callbacks> mCallbacks;
     Animation* mAnimation = nullptr;
+    GLuint mImageShader;
+    GLuint mTextShader;
+    GLuint mImageFadeLocation;
+    GLuint mImageTextureLocation;
+    GLuint mTextCropAreaLocation;
+    GLuint mTextTextureLocation;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index bdbbe2a..cc45589 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -56,9 +56,6 @@
         "-readability-redundant-access-specifiers",
         "-readability-uppercase-literal-suffix",
     ],
-    tidy_flags: [
-        "-system-headers",
-    ],
 }
 
 cc_library {
diff --git a/core/api/current.txt b/core/api/current.txt
index a0489d1..dd7f377 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6980,7 +6980,7 @@
   }
 
   public static interface WallpaperManager.OnColorsChangedListener {
-    method public void onColorsChanged(android.app.WallpaperColors, int);
+    method public void onColorsChanged(@Nullable android.app.WallpaperColors, int);
   }
 
   public interface ZygotePreload {
@@ -9124,6 +9124,7 @@
     field public static final int GATT_CONNECTION_CONGESTED = 143; // 0x8f
     field public static final int GATT_FAILURE = 257; // 0x101
     field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
+    field public static final int GATT_INSUFFICIENT_AUTHORIZATION = 8; // 0x8
     field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
     field public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 13; // 0xd
     field public static final int GATT_INVALID_OFFSET = 7; // 0x7
@@ -25266,13 +25267,17 @@
   public final class MediaSessionManager {
     method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName);
     method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, @Nullable android.os.Handler);
+    method public void addOnMediaKeyEventSessionChangedListener(@NonNull android.content.ComponentName, @NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
     method public void addOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
     method public void addOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener, @NonNull android.os.Handler);
     method @NonNull public java.util.List<android.media.session.MediaController> getActiveSessions(@Nullable android.content.ComponentName);
+    method @Nullable public android.media.session.MediaSession.Token getMediaKeyEventSession(@NonNull android.content.ComponentName);
+    method @NonNull public String getMediaKeyEventSessionPackageName(@NonNull android.content.ComponentName);
     method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
     method public boolean isTrustedForMediaControl(@NonNull android.media.session.MediaSessionManager.RemoteUserInfo);
     method @Deprecated public void notifySession2Created(@NonNull android.media.Session2Token);
     method public void removeOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
+    method public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
     method public void removeOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
   }
 
@@ -25280,6 +25285,10 @@
     method public void onActiveSessionsChanged(@Nullable java.util.List<android.media.session.MediaController>);
   }
 
+  public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
+    method public void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token);
+  }
+
   public static interface MediaSessionManager.OnSession2TokensChangedListener {
     method public void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>);
   }
@@ -31676,6 +31685,7 @@
     method public boolean isDeviceIdleMode();
     method public boolean isIgnoringBatteryOptimizations(String);
     method public boolean isInteractive();
+    method public boolean isLightDeviceIdleMode();
     method public boolean isPowerSaveMode();
     method public boolean isRebootingUserspaceSupported();
     method @Deprecated public boolean isScreenOn();
@@ -31686,6 +31696,7 @@
     method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
     field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
+    field public static final String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
     field public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
     field @Deprecated public static final int FULL_WAKE_LOCK = 26; // 0x1a
     field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2
@@ -34824,6 +34835,7 @@
   }
 
   public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
+    field public static final String ACTION_SET_DEFAULT_ACCOUNT = "android.provider.action.SET_DEFAULT_ACCOUNT";
     field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
     field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
     field public static final android.net.Uri CONTENT_URI;
@@ -51933,7 +51945,7 @@
     method public boolean finishComposingText();
     method public int getCursorCapsMode(int);
     method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
-    method public android.os.Handler getHandler();
+    method @Nullable public android.os.Handler getHandler();
     method public CharSequence getSelectedText(int);
     method @Nullable public default android.view.inputmethod.SurroundingText getSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
     method @Nullable public CharSequence getTextAfterCursor(@IntRange(from=0) int, int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 96c990d..2c2e811 100755
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2107,6 +2107,7 @@
     field @NonNull public static final android.os.ParcelUuid BASE_UUID;
     field @NonNull public static final android.os.ParcelUuid BNEP;
     field @NonNull public static final android.os.ParcelUuid DIP;
+    field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL;
     field @NonNull public static final android.os.ParcelUuid HEARING_AID;
     field @NonNull public static final android.os.ParcelUuid HFP;
     field @NonNull public static final android.os.ParcelUuid HFP_AG;
@@ -2117,6 +2118,7 @@
     field @NonNull public static final android.os.ParcelUuid LE_AUDIO;
     field @NonNull public static final android.os.ParcelUuid MAP;
     field @NonNull public static final android.os.ParcelUuid MAS;
+    field @NonNull public static final android.os.ParcelUuid MEDIA_CONTROL;
     field @NonNull public static final android.os.ParcelUuid MNS;
     field @NonNull public static final android.os.ParcelUuid NAP;
     field @NonNull public static final android.os.ParcelUuid OBEX_OBJECT_PUSH;
@@ -2831,6 +2833,9 @@
     field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
     field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
     field public static final int RESTRICTION_NONE = 0; // 0x0
+    field public static final int ROLLBACK_DATA_POLICY_RESTORE = 0; // 0x0
+    field public static final int ROLLBACK_DATA_POLICY_RETAIN = 2; // 0x2
+    field public static final int ROLLBACK_DATA_POLICY_WIPE = 1; // 0x1
     field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0
     field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1
     field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2
@@ -5587,7 +5592,6 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.media.session.MediaSession.Token getMediaKeyEventSession();
     method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public String getMediaKeyEventSessionPackageName();
     method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
   }
@@ -5596,10 +5600,6 @@
     method public void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @Nullable android.media.session.MediaSession.Token);
   }
 
-  public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
-    method public void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token);
-  }
-
   public static interface MediaSessionManager.OnMediaKeyListener {
     method public boolean onMediaKey(android.view.KeyEvent);
   }
@@ -6020,6 +6020,7 @@
     method public static int getTunerVersion();
     field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000
     field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001
+    field public static final int TUNER_VERSION_2_0 = 131072; // 0x20000
     field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0
   }
 
@@ -7028,13 +7029,13 @@
     field public static final long FEC_23_36 = 268435456L; // 0x10000000L
     field public static final long FEC_25_36 = 536870912L; // 0x20000000L
     field public static final long FEC_26_45 = 1073741824L; // 0x40000000L
-    field public static final long FEC_28_45 = -2147483648L; // 0xffffffff80000000L
-    field public static final long FEC_29_45 = 1L; // 0x1L
+    field public static final long FEC_28_45 = 2147483648L; // 0x80000000L
+    field public static final long FEC_29_45 = 4294967296L; // 0x100000000L
     field public static final long FEC_2_3 = 32L; // 0x20L
     field public static final long FEC_2_5 = 64L; // 0x40L
     field public static final long FEC_2_9 = 128L; // 0x80L
-    field public static final long FEC_31_45 = 2L; // 0x2L
-    field public static final long FEC_32_45 = 4L; // 0x4L
+    field public static final long FEC_31_45 = 8589934592L; // 0x200000000L
+    field public static final long FEC_32_45 = 17179869184L; // 0x400000000L
     field public static final long FEC_3_4 = 256L; // 0x100L
     field public static final long FEC_3_5 = 512L; // 0x200L
     field public static final long FEC_4_15 = 2048L; // 0x800L
@@ -7042,7 +7043,7 @@
     field public static final long FEC_5_6 = 4096L; // 0x1000L
     field public static final long FEC_5_9 = 8192L; // 0x2000L
     field public static final long FEC_6_7 = 16384L; // 0x4000L
-    field public static final long FEC_77_90 = 8L; // 0x8L
+    field public static final long FEC_77_90 = 34359738368L; // 0x800000000L
     field public static final long FEC_7_15 = 131072L; // 0x20000L
     field public static final long FEC_7_8 = 32768L; // 0x8000L
     field public static final long FEC_7_9 = 65536L; // 0x10000L
@@ -9126,6 +9127,7 @@
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
     field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
+    field public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
     field public static final String NAMESPACE_LOCATION = "location";
     field public static final String NAMESPACE_MEDIA = "media";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 3a883d8..427bbd8 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -323,6 +323,23 @@
     },
 }
 
+aidl_interface {
+    name: "android.debug_aidl",
+    unstable: true,
+    srcs: [
+        "android/debug/AdbTransportType.aidl",
+        "android/debug/FingerprintAndPairDevice.aidl",
+        "android/debug/IAdbCallback.aidl",
+        "android/debug/IAdbManager.aidl",
+        "android/debug/PairDevice.aidl",
+    ],
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+    },
+}
+
 // Avoid including Parcelable classes as we don't want to have two copies of
 // Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
 // and TeleService app (packages/services/Telephony).
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index eb913dd..70ee7d7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1518,6 +1518,17 @@
         getApplication().dispatchActivityPostDestroyed(this);
     }
 
+    private void dispatchActivityConfigurationChanged() {
+        getApplication().dispatchActivityConfigurationChanged(this);
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((Application.ActivityLifecycleCallbacks) callbacks[i])
+                        .onActivityConfigurationChanged(this);
+            }
+        }
+    }
+
     private Object[] collectActivityLifecycleCallbacks() {
         Object[] callbacks = null;
         synchronized (mActivityLifecycleCallbacks) {
@@ -2944,6 +2955,8 @@
             // view changes from above.
             mActionBar.onConfigurationChanged(newConfig);
         }
+
+        dispatchActivityConfigurationChanged();
     }
 
     /**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 8e1f263..76f8731 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -215,6 +215,14 @@
             "android.activity.launchRootTaskToken";
 
     /**
+     * The {@link com.android.server.wm.TaskFragment} token the activity should be launched into.
+     * @see #setLaunchTaskFragmentToken(IBinder)
+     * @hide
+     */
+    public static final String KEY_LAUNCH_TASK_FRAGMENT_TOKEN =
+            "android.activity.launchTaskFragmentToken";
+
+    /**
      * The windowing mode the activity should be launched into.
      * @hide
      */
@@ -396,6 +404,7 @@
     private int mCallerDisplayId = INVALID_DISPLAY;
     private WindowContainerToken mLaunchTaskDisplayArea;
     private WindowContainerToken mLaunchRootTask;
+    private IBinder mLaunchTaskFragmentToken;
     @WindowConfiguration.WindowingMode
     private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
     @WindowConfiguration.ActivityType
@@ -1138,6 +1147,7 @@
         mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
         mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
         mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
+        mLaunchTaskFragmentToken = opts.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
         mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
         mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
@@ -1473,6 +1483,17 @@
     }
 
     /** @hide */
+    public IBinder getLaunchTaskFragmentToken() {
+        return mLaunchTaskFragmentToken;
+    }
+
+    /** @hide */
+    public ActivityOptions setLaunchTaskFragmentToken(IBinder taskFragmentToken) {
+        mLaunchTaskFragmentToken = taskFragmentToken;
+        return this;
+    }
+
+    /** @hide */
     public int getLaunchWindowingMode() {
         return mLaunchWindowingMode;
     }
@@ -1882,6 +1903,9 @@
         if (mLaunchRootTask != null) {
             b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
         }
+        if (mLaunchTaskFragmentToken != null) {
+            b.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, mLaunchTaskFragmentToken);
+        }
         if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
             b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3abe4d..ae812ec 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -371,11 +371,12 @@
     @UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
             publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
     Configuration mConfiguration;
+    @GuardedBy("this")
+    private boolean mUpdateHttpProxyOnBind = false;
     @UnsupportedAppUsage
     Application mInitialApplication;
     @UnsupportedAppUsage
-    final ArrayList<Application> mAllApplications
-            = new ArrayList<Application>();
+    final ArrayList<Application> mAllApplications = new ArrayList<>();
     /**
      * Bookkeeping of instantiated backup agents indexed first by user id, then by package name.
      * Indexing by user id supports parallel backups across users on system packages as they run in
@@ -529,6 +530,9 @@
         // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
         // used without security checks
         public IBinder shareableActivityToken;
+        // The token of the initial TaskFragment that embedded this activity. Do not rely on it
+        // after creation because the activity could be reparented.
+        @Nullable public IBinder mInitialTaskFragmentToken;
         int ident;
         @UnsupportedAppUsage
         Intent intent;
@@ -622,7 +626,8 @@
                 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
-                IBinder shareableActivityToken, boolean launchedFromBubble) {
+                IBinder shareableActivityToken, boolean launchedFromBubble,
+                IBinder initialTaskFragmentToken) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -644,6 +649,7 @@
             mActivityOptions = activityOptions;
             mPendingFixedRotationAdjustments = fixedRotationAdjustments;
             mLaunchedFromBubble = launchedFromBubble;
+            mInitialTaskFragmentToken = initialTaskFragmentToken;
             init();
         }
 
@@ -1189,8 +1195,18 @@
         }
 
         public void updateHttpProxy() {
-            ActivityThread.updateHttpProxy(
-                    getApplication() != null ? getApplication() : getSystemContext());
+            final Application app;
+            synchronized (ActivityThread.this) {
+                app = getApplication();
+                if (null == app) {
+                    // The app is not bound yet. Make a note to update the HTTP proxy when the
+                    // app is bound.
+                    mUpdateHttpProxyOnBind = true;
+                    return;
+                }
+            }
+            // App is present, update the proxy inline.
+            ActivityThread.updateHttpProxy(app);
         }
 
         public void processInBackground() {
@@ -5651,8 +5667,8 @@
      */
     private void scheduleRelaunchActivityIfPossible(@NonNull ActivityClientRecord r,
             boolean preserveWindow) {
-        if (r.activity.mFinished || r.token instanceof Binder) {
-            // Do not schedule relaunch if the activity is finishing or not a local object (e.g.
+        if ((r.activity != null && r.activity.mFinished) || r.token instanceof Binder) {
+            // Do not schedule relaunch if the activity is finishing or is a local object (e.g.
             // created by ActivtiyGroup that server side doesn't recognize it).
             return;
         }
@@ -6657,6 +6673,15 @@
             sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
 
             mInitialApplication = app;
+            final boolean updateHttpProxy;
+            synchronized (this) {
+                updateHttpProxy = mUpdateHttpProxyOnBind;
+                // This synchronized block ensures that any subsequent call to updateHttpProxy()
+                // will see a non-null mInitialApplication.
+            }
+            if (updateHttpProxy) {
+                ActivityThread.updateHttpProxy(app);
+            }
 
             // don't bring up providers in restricted mode; they may depend on the
             // app's custom Application class
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4ddb546..d932a29 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2849,14 +2849,14 @@
     private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
 
     /**
-     * If a thread is currently executing a two-way binder transaction, this stores the
-     * ops that were noted blaming any app (the caller, the caller of the caller, etc).
+     * If a thread is currently executing a two-way binder transaction, this stores the op-codes of
+     * the app-ops that were noted during this transaction.
      *
      * @see #getNotedOpCollectionMode
      * @see #collectNotedOpSync
      */
-    private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>>
-            sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>();
+    private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
+            new ThreadLocal<>();
 
     /** Whether noting for an appop should be collected */
     private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
@@ -7205,6 +7205,34 @@
      * @hide
      */
     public interface OnOpStartedListener {
+
+        /**
+         * Represents a start operation that was unsuccessful
+         * @hide
+         */
+        public int START_TYPE_FAILED = 0;
+
+        /**
+         * Represents a successful start operation
+         * @hide
+         */
+        public int START_TYPE_STARTED = 1;
+
+        /**
+         * Represents an operation where a restricted operation became unrestricted, and resumed.
+         * @hide
+         */
+        public int START_TYPE_RESUMED = 2;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+            START_TYPE_FAILED,
+            START_TYPE_STARTED,
+            START_TYPE_RESUMED
+        })
+        public @interface StartedType {}
+
         /**
          * Called when an op was started.
          *
@@ -7213,11 +7241,35 @@
          * @param uid The UID performing the operation.
          * @param packageName The package performing the operation.
          * @param attributionTag The attribution tag performing the operation.
-         * @param flags The flags of this op
+         * @param flags The flags of this op.
          * @param result The result of the start.
          */
         void onOpStarted(int op, int uid, String packageName, String attributionTag,
                 @OpFlags int flags, @Mode int result);
+
+        /**
+         * Called when an op was started.
+         *
+         * Note: This is only for op starts. It is not called when an op is noted or stopped.
+         * By default, unless this method is overridden, no code will be executed for resume
+         * events.
+         * @param op The op code.
+         * @param uid The UID performing the operation.
+         * @param packageName The package performing the operation.
+         * @param attributionTag The attribution tag performing the operation.
+         * @param flags The flags of this op.
+         * @param result The result of the start.
+         * @param startType The start type of this start event. Either failed, resumed, or started.
+         * @param attributionFlags The location of this started op in an attribution chain.
+         * @param attributionChainId The ID of the attribution chain of this op, if it is in one.
+         */
+        default void onOpStarted(int op, int uid, String packageName, String attributionTag,
+                @OpFlags int flags, @Mode int result, @StartedType int startType,
+                @AttributionFlags int attributionFlags, int attributionChainId) {
+            if (startType != START_TYPE_RESUMED) {
+                onOpStarted(op, uid, packageName, attributionTag, flags, result);
+            }
+        }
     }
 
     AppOpsManager(Context context, IAppOpsService service) {
@@ -7858,8 +7910,10 @@
              cb = new IAppOpsStartedCallback.Stub() {
                  @Override
                  public void opStarted(int op, int uid, String packageName, String attributionTag,
-                         int flags, int mode) {
-                     callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode);
+                         int flags, int mode, int startType, int attributionFlags,
+                         int attributionChainId) {
+                     callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode,
+                             startType, attributionFlags, attributionChainId);
                  }
              };
              mStartedWatchers.put(callback, cb);
@@ -9052,6 +9106,66 @@
     }
 
     /**
+     * State of a temporarily paused noted app-ops collection.
+     *
+     * @see #pauseNotedAppOpsCollection()
+     *
+     * @hide
+     */
+    public static class PausedNotedAppOpsCollection {
+        final int mUid;
+        final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps;
+
+        PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String,
+                long[]> collectedNotedAppOps) {
+            mUid = uid;
+            mCollectedNotedAppOps = collectedNotedAppOps;
+        }
+    }
+
+    /**
+     * Temporarily suspend collection of noted app-ops when binder-thread calls into the other
+     * process. During such a call there might be call-backs coming back on the same thread which
+     * should not be accounted to the current collection.
+     *
+     * @return a state needed to resume the collection
+     *
+     * @hide
+     */
+    public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() {
+        Integer previousUid = sBinderThreadCallingUid.get();
+        if (previousUid != null) {
+            ArrayMap<String, long[]> previousCollectedNotedAppOps =
+                    sAppOpsNotedInThisBinderTransaction.get();
+
+            sBinderThreadCallingUid.remove();
+            sAppOpsNotedInThisBinderTransaction.remove();
+
+            return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps);
+        }
+
+        return null;
+    }
+
+    /**
+     * Resume a collection paused via {@link #pauseNotedAppOpsCollection}.
+     *
+     * @param prevCollection The state of the previous collection
+     *
+     * @hide
+     */
+    public static void resumeNotedAppOpsCollection(
+            @Nullable PausedNotedAppOpsCollection prevCollection) {
+        if (prevCollection != null) {
+            sBinderThreadCallingUid.set(prevCollection.mUid);
+
+            if (prevCollection.mCollectedNotedAppOps != null) {
+                sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps);
+            }
+        }
+    }
+
+    /**
      * Finish collection of noted appops on this thread.
      *
      * <p>Called at the end of a two way binder transaction.
@@ -9091,47 +9205,26 @@
      */
     @TestApi
     public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) {
-        collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(),
-                syncOp.getPackageName());
-    }
-
-    /**
-     * Collect a noted op when inside of a two-way binder call.
-     *
-     * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
-     *
-     * @param code the op code to note for
-     * @param attributionTag the attribution tag to note for
-     * @param packageName the package to note for
-     */
-    private static void collectNotedOpSync(int code, @Nullable String attributionTag,
-            @NonNull String packageName) {
         // If this is inside of a two-way binder call:
         // We are inside of a two-way binder call. Delivered to caller via
         // {@link #prefixParcelWithAppOpsIfNeeded}
-        ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted =
-                sAppOpsNotedInThisBinderTransaction.get();
+        int op = sOpStrToOp.get(syncOp.getOp());
+        ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
         if (appOpsNoted == null) {
             appOpsNoted = new ArrayMap<>(1);
             sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
         }
 
-        ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName);
-        if (packageAppOpsNotedForAttribution == null) {
-            packageAppOpsNotedForAttribution = new ArrayMap<>(1);
-            appOpsNoted.put(packageName, packageAppOpsNotedForAttribution);
-        }
-
-        long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag);
+        long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag());
         if (appOpsNotedForAttribution == null) {
             appOpsNotedForAttribution = new long[2];
-            packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution);
+            appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution);
         }
 
-        if (code < 64) {
-            appOpsNotedForAttribution[0] |= 1L << code;
+        if (op < 64) {
+            appOpsNotedForAttribution[0] |= 1L << op;
         } else {
-            appOpsNotedForAttribution[1] |= 1L << (code - 64);
+            appOpsNotedForAttribution[1] |= 1L << (op - 64);
         }
     }
 
@@ -9185,7 +9278,9 @@
             }
         }
 
-        if (isListeningForOpNotedInBinderTransaction()) {
+        Integer binderUid = sBinderThreadCallingUid.get();
+
+        if (binderUid != null && binderUid == uid) {
             return COLLECT_SYNC;
         } else {
             return COLLECT_ASYNC;
@@ -9204,32 +9299,20 @@
      */
     // TODO (b/186872903) Refactor how sync noted ops are propagated.
     public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) {
-        if (!isListeningForOpNotedInBinderTransaction()) {
-            return;
-        }
-        final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps =
-                sAppOpsNotedInThisBinderTransaction.get();
+        ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get();
         if (notedAppOps == null) {
             return;
         }
 
         p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
 
-        final int packageCount = notedAppOps.size();
-        p.writeInt(packageCount);
+        int numAttributionWithNotesAppOps = notedAppOps.size();
+        p.writeInt(numAttributionWithNotesAppOps);
 
-        for (int i = 0; i < packageCount; i++) {
+        for (int i = 0; i < numAttributionWithNotesAppOps; i++) {
             p.writeString(notedAppOps.keyAt(i));
-
-            final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i);
-            final int tagCount = notedTagAppOps.size();
-            p.writeInt(tagCount);
-
-            for (int j = 0; j < tagCount; j++) {
-                p.writeString(notedTagAppOps.keyAt(j));
-                p.writeLong(notedTagAppOps.valueAt(j)[0]);
-                p.writeLong(notedTagAppOps.valueAt(j)[1]);
-            }
+            p.writeLong(notedAppOps.valueAt(i)[0]);
+            p.writeLong(notedAppOps.valueAt(i)[1]);
         }
     }
 
@@ -9244,54 +9327,36 @@
      * @hide
      */
     public static void readAndLogNotedAppops(@NonNull Parcel p) {
-        final int packageCount = p.readInt();
-        if (packageCount <= 0) {
-            return;
-        }
+        int numAttributionsWithNotedAppOps = p.readInt();
 
-        final String myPackageName = ActivityThread.currentPackageName();
+        for (int i = 0; i < numAttributionsWithNotedAppOps; i++) {
+            String attributionTag = p.readString();
+            long[] rawNotedAppOps = new long[2];
+            rawNotedAppOps[0] = p.readLong();
+            rawNotedAppOps[1] = p.readLong();
 
-        synchronized (sLock) {
-            for (int i = 0; i < packageCount; i++) {
-                final String packageName = p.readString();
+            if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) {
+                BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
 
-                final int tagCount = p.readInt();
-                for (int j = 0; j < tagCount; j++) {
-                    final String attributionTag = p.readString();
-                    final long[] rawNotedAppOps = new long[2];
-                    rawNotedAppOps[0] = p.readLong();
-                    rawNotedAppOps[1] = p.readLong();
-
-                    if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) {
-                        continue;
-                    }
-
-                    final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
+                synchronized (sLock) {
                     for (int code = notedAppOps.nextSetBit(0); code != -1;
                             code = notedAppOps.nextSetBit(code + 1)) {
-                        if (Objects.equals(myPackageName, packageName)) {
-                            if (sOnOpNotedCallback != null) {
-                                sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code,
-                                        attributionTag, packageName));
-                            } else {
-                                String message = getFormattedStackTrace();
-                                sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(),
-                                        attributionTag, message, System.currentTimeMillis()));
-                                if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
-                                    sUnforwardedOps.remove(0);
-                                }
+                        if (sOnOpNotedCallback != null) {
+                            sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
+                        } else {
+                            String message = getFormattedStackTrace();
+                            sUnforwardedOps.add(
+                                    new AsyncNotedAppOp(code, Process.myUid(), attributionTag,
+                                            message, System.currentTimeMillis()));
+                            if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+                                sUnforwardedOps.remove(0);
                             }
-                        } else if (isListeningForOpNotedInBinderTransaction()) {
-                            collectNotedOpSync(code, attributionTag, packageName);
                         }
                     }
-                    for (int code = notedAppOps.nextSetBit(0); code != -1;
-                            code = notedAppOps.nextSetBit(code + 1)) {
-                        if (Objects.equals(myPackageName, packageName)) {
-                            sMessageCollector.onNoted(new SyncNotedAppOp(code,
-                                    attributionTag, packageName));
-                        }
-                    }
+                }
+                for (int code = notedAppOps.nextSetBit(0); code != -1;
+                        code = notedAppOps.nextSetBit(code + 1)) {
+                    sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag));
                 }
             }
         }
@@ -9398,15 +9463,7 @@
      * @hide
      */
     public static boolean isListeningForOpNoted() {
-        return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction()
-                || isCollectingStackTraces();
-    }
-
-    /**
-     * @return whether we are in a binder transaction and collecting appops.
-     */
-    private static boolean isListeningForOpNotedInBinderTransaction() {
-        return sBinderThreadCallingUid.get() != null;
+        return sOnOpNotedCallback != null || isCollectingStackTraces();
     }
 
     /**
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index f58ca6a..7f849ef 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -205,6 +205,13 @@
          */
         default void onActivityPostDestroyed(@NonNull Activity activity) {
         }
+
+        /**
+         * Called when the Activity configuration was changed.
+         * @hide
+         */
+        default void onActivityConfigurationChanged(@NonNull Activity activity) {
+        }
     }
 
     /**
@@ -554,6 +561,16 @@
         }
     }
 
+    /* package */ void dispatchActivityConfigurationChanged(@NonNull Activity activity) {
+        Object[] callbacks = collectActivityLifecycleCallbacks();
+        if (callbacks != null) {
+            for (int i = 0; i < callbacks.length; i++) {
+                ((ActivityLifecycleCallbacks) callbacks[i]).onActivityConfigurationChanged(
+                        activity);
+            }
+        }
+    }
+
     @UnsupportedAppUsage
     private Object[] collectActivityLifecycleCallbacks() {
         Object[] callbacks = null;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b81a8d3..7e4f9b4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1014,17 +1014,13 @@
                     }
                 }
                 @Override
-                protected boolean bypass(Integer uid) {
-                    return uid < 0;
-                }
-                @Override
                 public String queryToString(Integer uid) {
                     return String.format("uid=%d", uid.intValue());
                 }
             };
 
     @Override
-    public String[] getPackagesForUid(@UserIdInt int uid) {
+    public String[] getPackagesForUid(int uid) {
         return mGetPackagesForUidCache.query(uid).value();
     }
 
@@ -1039,7 +1035,7 @@
     }
 
     @Override
-    public String getNameForUid(@UserIdInt int uid) {
+    public String getNameForUid(int uid) {
         try {
             return mPM.getNameForUid(uid);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7114d73..d0acacf 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2260,7 +2260,7 @@
             int modeFlags) {
         try {
             return ActivityManager.getService().checkUriPermissions(uris, pid, uid, modeFlags,
-                    null);
+                    getUserId(), null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b90b9a1..6b738ff 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -221,7 +221,7 @@
     int getProcessLimit();
     int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId,
             in IBinder callerToken);
-    int[] checkUriPermissions(in List<Uri> uris, int pid, int uid, int mode,
+    int[] checkUriPermissions(in List<Uri> uris, int pid, int uid, int mode, int userId,
                 in IBinder callerToken);
     void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri,
             int mode, int userId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b2184fe..fd6589c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -743,6 +743,17 @@
         }
 
         /**
+         * This overload is used for notifying the {@link android.window.TaskFragmentOrganizer}
+         * implementation internally about started activities.
+         *
+         * @see #onStartActivity(Intent)
+         * @hide
+         */
+        public ActivityResult onStartActivity(Context who, Intent intent, Bundle options) {
+            return onStartActivity(intent);
+        }
+
+        /**
          * Used for intercepting any started activity.
          *
          * <p> A non-null return value here will be considered a hit for this monitor.
@@ -1722,7 +1733,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intent);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intent, options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -1790,7 +1804,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intents[0]);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intents[0], options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -1861,7 +1878,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intent);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intent, options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -1928,7 +1948,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intent);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intent, options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -1974,7 +1997,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intent);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intent, options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -2021,7 +2047,10 @@
                     final ActivityMonitor am = mActivityMonitors.get(i);
                     ActivityResult result = null;
                     if (am.ignoreMatchingSpecificIntents()) {
-                        result = am.onStartActivity(intent);
+                        if (options == null) {
+                            options = ActivityOptions.makeBasic().toBundle();
+                        }
+                        result = am.onStartActivity(who, intent, options);
                     }
                     if (result != null) {
                         am.mHits++;
@@ -2083,7 +2112,8 @@
                     throw new ActivityNotFoundException(
                             "Unable to find explicit activity class "
                             + ((Intent)intent).getComponent().toShortString()
-                            + "; have you declared this activity in your AndroidManifest.xml?");
+                            + "; have you declared this activity in your AndroidManifest.xml"
+                            + ", or does your intent not match its declared <intent-filter>?");
                 throw new ActivityNotFoundException(
                         "No Activity found to handle " + intent);
             case ActivityManager.START_PERMISSION_DENIED:
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ab88e6c..908af96 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6120,28 +6120,29 @@
                 // change the background bgColor
                 CharSequence title = action.title;
                 ColorStateList[] outResultColor = new ColorStateList[1];
-                int background = getColors(p).getSecondaryAccentColor();
+                int buttonFillColor = getColors(p).getSecondaryAccentColor();
                 if (isLegacy()) {
                     title = ContrastColorUtil.clearColorSpans(title);
                 } else {
-                    title = ensureColorSpanContrast(title, background, outResultColor);
+                    int notifBackgroundColor = getColors(p).getBackgroundColor();
+                    title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
                 }
                 button.setTextViewText(R.id.action0, processTextSpans(title));
                 boolean hasColorOverride = outResultColor[0] != null;
                 if (hasColorOverride) {
                     // There's a span spanning the full text, let's take it and use it as the
                     // background color
-                    background = outResultColor[0].getDefaultColor();
+                    buttonFillColor = outResultColor[0].getDefaultColor();
                 }
                 final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
-                        background, mInNightMode);
+                        buttonFillColor, mInNightMode);
                 button.setTextColor(R.id.action0, textColor);
                 // We only want about 20% alpha for the ripple
                 final int rippleColor = (textColor & 0x00ffffff) | 0x33000000;
                 button.setColorStateList(R.id.action0, "setRippleColor",
                         ColorStateList.valueOf(rippleColor));
                 button.setColorStateList(R.id.action0, "setButtonBackground",
-                        ColorStateList.valueOf(background));
+                        ColorStateList.valueOf(buttonFillColor));
                 if (p.mCallStyleActions) {
                     button.setImageViewIcon(R.id.action0, action.getIcon());
                     boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
@@ -6174,8 +6175,8 @@
          *                    there exists a full length color span.
          * @return the contrasted charSequence
          */
-        private CharSequence ensureColorSpanContrast(CharSequence charSequence, int background,
-                ColorStateList[] outResultColor) {
+        private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
+                int background, ColorStateList[] outResultColor) {
             if (charSequence instanceof Spanned) {
                 Spanned ss = (Spanned) charSequence;
                 Object[] spans = ss.getSpans(0, ss.length(), Object.class);
@@ -6195,8 +6196,9 @@
                             int[] colors = textColor.getColors();
                             int[] newColors = new int[colors.length];
                             for (int i = 0; i < newColors.length; i++) {
+                                boolean isBgDark = isColorDark(background);
                                 newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
-                                        colors[i], background, mInNightMode);
+                                        colors[i], background, isBgDark);
                             }
                             textColor = new ColorStateList(textColor.getStates().clone(),
                                     newColors);
@@ -6215,8 +6217,9 @@
                     } else if (resultSpan instanceof ForegroundColorSpan) {
                         ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
                         int foregroundColor = originalSpan.getForegroundColor();
+                        boolean isBgDark = isColorDark(background);
                         foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
-                                foregroundColor, background, mInNightMode);
+                                foregroundColor, background, isBgDark);
                         if (fullLength) {
                             outResultColor[0] = ColorStateList.valueOf(foregroundColor);
                             resultSpan = null;
@@ -6236,6 +6239,19 @@
         }
 
         /**
+         * Determines if the color is light or dark.  Specifically, this is using the same metric as
+         * {@link ContrastColorUtil#resolvePrimaryColor(Context, int, boolean)} and peers so that
+         * the direction of color shift is consistent.
+         *
+         * @param color the color to check
+         * @return true if the color has higher contrast with white than black
+         */
+        private static boolean isColorDark(int color) {
+            // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
+            return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
+        }
+
+        /**
          * @return Whether we are currently building a notification from a legacy (an app that
          *         doesn't create material notifications by itself) app.
          */
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index 32d889e..7c0c08a 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcelable;
-import android.os.Process;
 
 import com.android.internal.annotations.Immutable;
 import com.android.internal.util.DataClass;
@@ -29,6 +28,8 @@
 /**
  * Description of an app-op that was noted for the current process.
  *
+ * Note: package name is currently unused in the system.
+ *
  * <p>This is either delivered after a
  * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
  * when the app
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8d332ab..84752be 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -66,6 +66,7 @@
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemProperties;
+import android.service.wallpaper.WallpaperService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -221,6 +222,20 @@
     public static final String COMMAND_REAPPLY = "android.wallpaper.reapply";
 
     /**
+     * Command for {@link #sendWallpaperCommand}: reported when the live wallpaper needs to be
+     * frozen.
+     * @hide
+     */
+    public static final String COMMAND_FREEZE = "android.wallpaper.freeze";
+
+    /**
+     * Command for {@link #sendWallpaperCommand}: reported when the live wallapper doesn't need
+     * to be frozen anymore.
+     * @hide
+     */
+    public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze";
+
+    /**
      * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
      * @hide
      */
@@ -2316,22 +2331,24 @@
          * A {@link android.app.WallpaperColors} object containing a simplified
          * color histogram will be given.
          *
-         * @param colors Wallpaper color info
+         * @param colors Wallpaper color info, {@code null} when not available.
          * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
+         * @see WallpaperService.Engine#onComputeColors()
          */
-        void onColorsChanged(WallpaperColors colors, int which);
+        void onColorsChanged(@Nullable WallpaperColors colors, int which);
 
         /**
          * Called when colors change.
          * A {@link android.app.WallpaperColors} object containing a simplified
          * color histogram will be given.
          *
-         * @param colors Wallpaper color info
+         * @param colors Wallpaper color info, {@code null} when not available.
          * @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
          * @param userId Owner of the wallpaper
+         * @see WallpaperService.Engine#onComputeColors()
          * @hide
          */
-        default void onColorsChanged(WallpaperColors colors, int which, int userId) {
+        default void onColorsChanged(@Nullable WallpaperColors colors, int which, int userId) {
             onColorsChanged(colors, which);
         }
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a37d04..4b401a5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10596,11 +10596,16 @@
      * behavior of this API is changed such that passing {@code null} as the {@code admin} parameter
      * will return if any admin has blocked the uninstallation. Before L MR1, passing {@code null}
      * will cause a NullPointerException to be raised.
+     * <p>
+     * <strong>Note:</strong> If your app targets Android 11 (API level 30) or higher,
+     * this method returns a filtered result. Learn more about how to
+     * <a href="/training/basics/intents/package-visibility">manage package visibility</a>.
      *
      * @param admin The name of the admin component whose blocking policy will be checked, or
      *            {@code null} to check whether any admin has blocked the uninstallation.
      * @param packageName package to check.
-     * @return true if uninstallation is blocked.
+     * @return true if uninstallation is blocked and the given package is visible to you, false
+     *         otherwise if uninstallation isn't blocked or the given package isn't visible to you.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
     public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fc4a2b4..e1f6af0 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -658,6 +658,7 @@
         float mElevation;
         float mAlpha = 1.0f;
 
+        // TODO: The FLAGS_* below have filled all bits, will need to be refactored.
         static final int FLAGS_DISABLED = 0x00000001;
         static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
         static final int FLAGS_FOCUSABLE = 0x00000010;
@@ -673,6 +674,10 @@
         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
         static final int FLAGS_OPAQUE = 0x00008000;
 
+        // --IMPORTANT-- must update this flag if any below flags extend to further bits.
+        // This flag is used to clear all FLAGS_HAS_* values in mFlags prior to parceling.
+        static final int FLAGS_ALL_CONTROL = 0xffff0000;
+
         static final int FLAGS_HAS_MIME_TYPES = 0x80000000;
         static final int FLAGS_HAS_MATRIX = 0x40000000;
         static final int FLAGS_HAS_ALPHA = 0x20000000;
@@ -689,7 +694,7 @@
         static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
         static final int FLAGS_HAS_URL_SCHEME = 0x00020000;
         static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
-        static final int FLAGS_ALL_CONTROL = 0xfff00000;
+        // --IMPORTANT END--
 
         static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID =         0x0001;
         static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x0002;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 1b03f2f..bf9a9b0 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -116,7 +116,7 @@
         ConfigSection.CLOUD_BACKUP,
         ConfigSection.DEVICE_TRANSFER
     })
-    private @interface ConfigSection {
+    @interface ConfigSection {
         String CLOUD_BACKUP = "cloud-backup";
         String DEVICE_TRANSFER = "device-transfer";
     }
@@ -528,7 +528,8 @@
             return mExcludes;
         }
 
-        private synchronized int getRequiredTransportFlags()
+        @VisibleForTesting
+        public synchronized int getRequiredTransportFlags()
                 throws IOException, XmlPullParserException {
             if (mRequiredTransportFlags == null) {
                 maybeParseBackupSchemeLocked();
@@ -587,11 +588,13 @@
             if (mDataExtractionRules != 0) {
                 // New config is present. Use it if it has configuration for this operation
                 // type.
+                boolean isSectionPresent;
                 try (XmlResourceParser parser = getParserForResource(mDataExtractionRules)) {
-                    parseNewBackupSchemeFromXmlLocked(parser, configSection, mExcludes, mIncludes);
+                    isSectionPresent = parseNewBackupSchemeFromXmlLocked(parser, configSection,
+                            mExcludes, mIncludes);
                 }
-                if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
-                    // Found configuration in the new config, we will use it.
+                if (isSectionPresent) {
+                    // Found the relevant section in the new config, we will use it.
                     mIsUsingNewScheme = true;
                     return;
                 }
@@ -630,24 +633,31 @@
                     .getXml(resourceId);
         }
 
-        private void parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
+        @VisibleForTesting
+        public boolean parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
                 @ConfigSection  String configSection,
                 Set<PathWithRequiredFlags> excludes,
                 Map<String, Set<PathWithRequiredFlags>> includes)
                 throws IOException, XmlPullParserException {
             verifyTopLevelTag(parser, "data-extraction-rules");
 
+            boolean isSectionPresent = false;
+
             int event;
             while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (event != XmlPullParser.START_TAG || !configSection.equals(parser.getName())) {
                     continue;
                 }
 
+                isSectionPresent = true;
+
                 parseRequiredTransportFlags(parser, configSection);
                 parseRules(parser, excludes, includes, Optional.of(0), configSection);
             }
 
             logParsingResults(excludes, includes);
+
+            return isSectionPresent;
         }
 
         private void parseRequiredTransportFlags(XmlPullParser parser,
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 34e4fcd..37cbccb 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -73,6 +73,7 @@
     private IBinder mAssistToken;
     private IBinder mShareableActivityToken;
     private boolean mLaunchedFromBubble;
+    private IBinder mTaskFragmentToken;
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -86,7 +87,7 @@
                 mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                 client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
-                mLaunchedFromBubble);
+                mLaunchedFromBubble, mTaskFragmentToken);
         client.addLaunchingActivity(token, r);
         client.updateProcessState(mProcState, false);
         client.updatePendingConfiguration(mCurConfig);
@@ -124,7 +125,7 @@
             boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
             IActivityClientController activityClientController,
             FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
-            boolean launchedFromBubble) {
+            boolean launchedFromBubble, IBinder taskFragmentToken) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -133,7 +134,7 @@
                 voiceInteractor, procState, state, persistentState, pendingResults,
                 pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
                 activityClientController, fixedRotationAdjustments, shareableActivityToken,
-                launchedFromBubble);
+                launchedFromBubble, taskFragmentToken);
 
         return instance;
     }
@@ -141,7 +142,7 @@
     @Override
     public void recycle() {
         setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null, null, false);
+                null, false, null, null, null, null, null, false, null);
         ObjectPool.recycle(this);
     }
 
@@ -172,6 +173,7 @@
         dest.writeTypedObject(mFixedRotationAdjustments, flags);
         dest.writeStrongBinder(mShareableActivityToken);
         dest.writeBoolean(mLaunchedFromBubble);
+        dest.writeStrongBinder(mTaskFragmentToken);
     }
 
     /** Read from Parcel. */
@@ -190,7 +192,8 @@
                 in.readStrongBinder(),
                 IActivityClientController.Stub.asInterface(in.readStrongBinder()),
                 in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder(),
-                in.readBoolean());
+                in.readBoolean(),
+                in.readStrongBinder());
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -229,7 +232,8 @@
                 && Objects.equals(mProfilerInfo, other.mProfilerInfo)
                 && Objects.equals(mAssistToken, other.mAssistToken)
                 && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments)
-                && Objects.equals(mShareableActivityToken, other.mShareableActivityToken);
+                && Objects.equals(mShareableActivityToken, other.mShareableActivityToken)
+                && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken);
     }
 
     @Override
@@ -252,6 +256,7 @@
         result = 31 * result + Objects.hashCode(mAssistToken);
         result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
         result = 31 * result + Objects.hashCode(mShareableActivityToken);
+        result = 31 * result + Objects.hashCode(mTaskFragmentToken);
         return result;
     }
 
@@ -301,7 +306,7 @@
             ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
             IBinder assistToken, IActivityClientController activityClientController,
             FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
-            boolean launchedFromBubble) {
+            boolean launchedFromBubble, IBinder taskFragmentToken) {
         instance.mIntent = intent;
         instance.mIdent = ident;
         instance.mInfo = info;
@@ -323,5 +328,6 @@
         instance.mFixedRotationAdjustments = fixedRotationAdjustments;
         instance.mShareableActivityToken = shareableActivityToken;
         instance.mLaunchedFromBubble = launchedFromBubble;
+        instance.mTaskFragmentToken = taskFragmentToken;
     }
 }
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index f506f12..17e9e93 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -50,10 +50,10 @@
     public static final String SHELL_COMMAND_STOP = "stop";
 
     /**
-     * A shell command that tells the service to record state information during tests. The next
-     * argument value is "true" or "false".
+     * A shell command that clears recorded provider state information during tests.
      */
-    public static final String SHELL_COMMAND_RECORD_PROVIDER_STATES = "record_provider_states";
+    public static final String SHELL_COMMAND_CLEAR_RECORDED_PROVIDER_STATES =
+            "clear_recorded_provider_states";
 
     /**
      * A shell command that tells the service to dump its current state.
@@ -65,44 +65,15 @@
      */
     public static final String DUMP_STATE_OPTION_PROTO = "--proto";
 
-    /**
-     * A shell command that sends test commands to a provider
-     */
-    public static final String SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND =
-            "send_provider_test_command";
+    /** A shell command that starts the location_time_zone_manager with named test providers. */
+    public static final String SHELL_COMMAND_START_WITH_TEST_PROVIDERS =
+            "start_with_test_providers";
 
     /**
-     * Simulated provider test command that simulates the bind succeeding.
+     * The token that can be passed to {@link #SHELL_COMMAND_START_WITH_TEST_PROVIDERS} to indicate
+     * there is no provider.
      */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_ON_BIND = "on_bind";
-
-    /**
-     * Simulated provider test command that simulates the provider unbinding.
-     */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_ON_UNBIND = "on_unbind";
-
-    /**
-     * Simulated provider test command that simulates the provider entering the "permanent failure"
-     * state.
-     */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_PERM_FAILURE = "perm_fail";
-
-    /**
-     * Simulated provider test command that simulates the provider entering the "success" (time
-     * zone(s) detected) state.
-     */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS = "success";
-
-    /**
-     * Argument for {@link #SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS} to specify TZDB time zone IDs.
-     */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS_ARG_KEY_TZ = "tz";
-
-    /**
-     * Simulated provider test command that simulates the provider entering the "uncertain"
-     * state.
-     */
-    public static final String SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN = "uncertain";
+    public static final String NULL_PACKAGE_NAME_TOKEN = "@null";
 
     private LocationTimeZoneManager() {
         // No need to instantiate.
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 65cdca9..1dd32fe 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -1025,6 +1025,10 @@
     public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
             int value) {
         if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
+        if (value < 0) {
+            Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value);
+            return false;
+        }
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()) {
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bbb550f..f68a8b2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1096,6 +1096,8 @@
     /** Address is either resolvable, non-resolvable or static. */
     public static final int ADDRESS_TYPE_RANDOM = 1;
 
+    private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
+
     /**
      * Lazy initialization. Guaranteed final after first object constructed, or
      * getService() called.
@@ -1493,6 +1495,10 @@
             Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
             return false;
         }
+        if (NULL_MAC_ADDRESS.equals(mAddress)) {
+            Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
+            return false;
+        }
         try {
             return service.createBond(
                     this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 17a3e48..65cdc83 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -108,6 +108,9 @@
     /** A read or write operation was requested with an invalid offset */
     public static final int GATT_INVALID_OFFSET = 0x7;
 
+    /** Insufficient authorization for a given operation */
+    public static final int GATT_INSUFFICIENT_AUTHORIZATION = 0x8;
+
     /** A write operation exceeds the maximum length of the attribute */
     public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd;
 
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 83a272fc..5b67a75 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -220,12 +220,19 @@
     int VOLUME_CONTROL = 23;
 
     /**
+     * @hide
+     * Media Control Profile server
+     *
+     */
+    int MCP_SERVER = 24;
+
+    /**
      * Max profile ID. This value should be updated whenever a new profile is added to match
      * the largest value assigned to a profile.
      *
      * @hide
      */
-    int MAX_PROFILE_ID = 23;
+    int MAX_PROFILE_ID = 24;
 
     /**
      * Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bc3754a..ff250e6 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -174,6 +174,16 @@
     /** @hide */
     @NonNull
     @SystemApi
+    public static final ParcelUuid GENERIC_MEDIA_CONTROL =
+            ParcelUuid.fromString("00001849-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid MEDIA_CONTROL =
+            ParcelUuid.fromString("00001848-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
 
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index cb3bf29..8ff0181 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -168,6 +168,15 @@
                 dest.writeByteArray(mManufacturerDataMask);
             }
         }
+
+        // IRK
+        if (mDeviceAddress != null) {
+            dest.writeInt(mAddressType);
+            dest.writeInt(mIrk == null ? 0 : 1);
+            if (mIrk != null) {
+                dest.writeByteArray(mIrk);
+            }
+        }
     }
 
     /**
@@ -187,8 +196,10 @@
             if (in.readInt() == 1) {
                 builder.setDeviceName(in.readString());
             }
+            String address = null;
+            // If we have a non-null address
             if (in.readInt() == 1) {
-                builder.setDeviceAddress(in.readString());
+                address = in.readString();
             }
             if (in.readInt() == 1) {
                 ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
@@ -245,6 +256,17 @@
                 }
             }
 
+            // IRK
+            if (address != null) {
+                final int addressType = in.readInt();
+                if (in.readInt() == 1) {
+                    final byte[] irk = new byte[16];
+                    in.readByteArray(irk);
+                    builder.setDeviceAddress(address, addressType, irk);
+                } else {
+                    builder.setDeviceAddress(address, addressType);
+                }
+            }
             return builder.build();
         }
     };
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a741f96..c714f507 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -745,9 +745,6 @@
         if (Binder.getCallingPid() == Process.myPid()) {
             return PermissionChecker.PERMISSION_GRANTED;
         }
-        if (!attributionSource.checkCallingUid()) {
-            return PermissionChecker.PERMISSION_HARD_DENIED;
-        }
         return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(getContext(),
                 permission, -1, new AttributionSource(getContext().getAttributionSource(),
                         attributionSource), /*message*/ null);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e109ae5..846349d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1866,7 +1866,7 @@
      * that should be managed by the launched UI.
      * </p>
      * <p>
-     * <li> {@link #EXTRA_USER} specifies the UserHandle of the user that owns the app.
+     * <li> {@link #EXTRA_USER} specifies the {@link UserHandle} of the user that owns the app.
      * </p>
      * <p>
      * Output: Nothing.
@@ -2850,8 +2850,8 @@
     public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
 
     /**
-     * Broadcast Action: A user ID has been removed from the system.  The user
-     * ID number is stored in the extra data under {@link #EXTRA_UID}.
+     * Broadcast Action: A uid has been removed from the system.  The uid
+     * number is stored in the extra data under {@link #EXTRA_UID}.
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -3726,10 +3726,12 @@
             "android.intent.action.USER_BACKGROUND";
 
     /**
-     * Broadcast sent to the system when a user is added. Carries an extra
-     * EXTRA_USER_HANDLE that has the userHandle of the new user.  It is sent to
-     * all running users.  You must hold
-     * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
+     * Broadcast sent to the system when a user is added.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the new user
+     * (and for legacy reasons, also carries an int extra {@link #EXTRA_USER_HANDLE} specifying that
+     * user's user ID).
+     * It is sent to all running users.
+     * You must hold {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
      */
     @SystemApi
@@ -3738,7 +3740,7 @@
 
     /**
      * Broadcast sent by the system when a user is started. Carries an extra
-     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only sent to
+     * {@link #EXTRA_USER_HANDLE} that has the user ID of the user.  This is only sent to
      * registered receivers, not manifest receivers.  It is sent to the user
      * that has been started.  This is sent as a foreground
      * broadcast, since it is part of a visible user interaction; be as quick
@@ -3750,7 +3752,7 @@
 
     /**
      * Broadcast sent when a user is in the process of starting.  Carries an extra
-     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only
+     * {@link #EXTRA_USER_HANDLE} that has the user ID of the user.  This is only
      * sent to registered receivers, not manifest receivers.  It is sent to all
      * users (including the one that is being started).  You must hold
      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
@@ -3767,7 +3769,7 @@
 
     /**
      * Broadcast sent when a user is going to be stopped.  Carries an extra
-     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is only
+     * {@link #EXTRA_USER_HANDLE} that has the user ID of the user.  This is only
      * sent to registered receivers, not manifest receivers.  It is sent to all
      * users (including the one that is being stopped).  You must hold
      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive
@@ -3785,7 +3787,7 @@
 
     /**
      * Broadcast sent to the system when a user is stopped. Carries an extra
-     * {@link EXTRA_USER_HANDLE} that has the userHandle of the user.  This is similar to
+     * {@link #EXTRA_USER_HANDLE} that has the user ID of the user.  This is similar to
      * {@link #ACTION_PACKAGE_RESTARTED}, but for an entire user instead of a
      * specific package.  This is only sent to registered receivers, not manifest
      * receivers.  It is sent to all running users <em>except</em> the one that
@@ -3797,8 +3799,12 @@
             "android.intent.action.USER_STOPPED";
 
     /**
-     * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
-     * the userHandle of the user.  It is sent to all running users except the
+     * Broadcast sent to the system when a user is removed.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the user that
+     * was removed
+     * (and for legacy reasons, also carries an int extra {@link #EXTRA_USER_HANDLE} specifying that
+     * user's user ID).
+     * It is sent to all running users except the
      * one that has been removed. The user will not be completely removed until all receivers have
      * handled the broadcast. You must hold
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
@@ -3809,9 +3815,13 @@
             "android.intent.action.USER_REMOVED";
 
     /**
-     * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USER_HANDLE that has
-     * the userHandle of the user to become the current one. This is only sent to
-     * registered receivers, not manifest receivers.  It is sent to all running users.
+     * Broadcast sent to the system when the user switches.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle}
+     * of the user to become the current one
+     * (and for legacy reasons, also carries an int extra {@link #EXTRA_USER_HANDLE} specifying that
+     * user's user ID).
+     * This is only sent to registered receivers, not manifest receivers.
+     * It is sent to all running users.
      * You must hold
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
@@ -3840,17 +3850,18 @@
     /**
      * Broadcast sent to the primary user when an associated managed profile is added (the profile
      * was created and is ready to be used). Carries an extra {@link #EXTRA_USER} that specifies
-     * the UserHandle of the profile that was added. Only applications (for example Launchers)
-     * that need to display merged content across both primary and managed profiles need to
-     * worry about this broadcast. This is only sent to registered receivers,
+     * the {@link UserHandle} of the profile that was added. Only applications (for example
+     * Launchers) that need to display merged content across both primary and managed profiles need
+     * to worry about this broadcast. This is only sent to registered receivers,
      * not manifest receivers.
      */
     public static final String ACTION_MANAGED_PROFILE_ADDED =
             "android.intent.action.MANAGED_PROFILE_ADDED";
 
     /**
-     * Broadcast sent to the primary user when an associated managed profile is removed. Carries an
-     * extra {@link #EXTRA_USER} that specifies the UserHandle of the profile that was removed.
+     * Broadcast sent to the primary user when an associated managed profile is removed.
+     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile
+     * that was removed.
      * Only applications (for example Launchers) that need to display merged content across both
      * primary and managed profiles need to worry about this broadcast. This is only sent to
      * registered receivers, not manifest receivers.
@@ -3861,9 +3872,9 @@
     /**
      * Broadcast sent to the primary user when the credential-encrypted private storage for
      * an associated managed profile is unlocked. Carries an extra {@link #EXTRA_USER} that
-     * specifies the UserHandle of the profile that was unlocked. Only applications (for example
-     * Launchers) that need to display merged content across both primary and managed profiles
-     * need to worry about this broadcast. This is only sent to registered receivers,
+     * specifies the {@link UserHandle} of the profile that was unlocked. Only applications (for
+     * example Launchers) that need to display merged content across both primary and managed
+     * profiles need to worry about this broadcast. This is only sent to registered receivers,
      * not manifest receivers.
      */
     public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
@@ -3872,9 +3883,9 @@
     /**
      * Broadcast sent to the primary user when an associated managed profile has become available.
      * Currently this includes when the user disables quiet mode for the profile. Carries an extra
-     * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
-     * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
-     * of quiet mode. This is only sent to registered receivers, not manifest receivers.
+     * {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile. When quiet mode is
+     * changed, this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the
+     * new state of quiet mode. This is only sent to registered receivers, not manifest receivers.
      */
     public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
             "android.intent.action.MANAGED_PROFILE_AVAILABLE";
@@ -3882,9 +3893,9 @@
     /**
      * Broadcast sent to the primary user when an associated managed profile has become unavailable.
      * Currently this includes when the user enables quiet mode for the profile. Carries an extra
-     * {@link #EXTRA_USER} that specifies the UserHandle of the profile. When quiet mode is changed,
-     * this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the new state
-     * of quiet mode. This is only sent to registered receivers, not manifest receivers.
+     * {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile. When quiet mode is
+     * changed, this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the
+     * new state of quiet mode. This is only sent to registered receivers, not manifest receivers.
      */
     public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
             "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
@@ -5339,7 +5350,7 @@
     public static final String EXTRA_INTENT = "android.intent.extra.INTENT";
 
     /**
-     * An int representing the user id to be used.
+     * An int representing the user ID to be used.
      *
      * @hide
      */
@@ -5933,7 +5944,7 @@
             "android.intent.extra.ALLOW_MULTIPLE";
 
     /**
-     * The integer userHandle (i.e. userId) carried with broadcast intents related to addition,
+     * The user ID integer carried with broadcast intents related to addition,
      * removal and switching of users and managed profiles - {@link #ACTION_USER_ADDED},
      * {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
      *
@@ -5943,7 +5954,7 @@
             "android.intent.extra.user_handle";
 
     /**
-     * The UserHandle carried with intents.
+     * The {@link UserHandle} carried with intents.
      */
     public static final String EXTRA_USER =
             "android.intent.extra.USER";
@@ -9418,7 +9429,7 @@
 
     /**
      * This is NOT a secure mechanism to identify the user who sent the intent.
-     * When the intent is sent to a different user, it is used to fix uris by adding the userId
+     * When the intent is sent to a different user, it is used to fix uris by adding the user ID
      * who sent the intent.
      * @hide
      */
@@ -11371,8 +11382,17 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void prepareToLeaveProcess(Context context) {
-        final boolean leavingPackage = (mComponent == null)
-                || !Objects.equals(mComponent.getPackageName(), context.getPackageName());
+        final boolean leavingPackage;
+        if (mComponent != null) {
+            leavingPackage = !Objects.equals(mComponent.getPackageName(), context.getPackageName());
+        } else if (mPackage != null) {
+            leavingPackage = !Objects.equals(mPackage, context.getPackageName());
+        } else {
+            // When no specific component or package has been defined, we have
+            // to assume that we might be routed through an intent
+            // disambiguation dialog which might leave our package
+            leavingPackage = true;
+        }
         prepareToLeaveProcess(leavingPackage);
     }
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3f8aedb..c2a65d5 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1616,7 +1616,7 @@
         /** {@hide} */
         public DataLoaderParams dataLoaderParams;
         /** {@hide} */
-        public int rollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
+        public int rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
         /** {@hide} */
         public boolean forceQueryableOverride;
         /** {@hide} */
@@ -1887,7 +1887,7 @@
             } else {
                 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
             }
-            rollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
+            rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
         }
 
         /**
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index dd2080b..2bac066 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -207,7 +207,9 @@
             return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
                     | SAFE_STRING_FLAG_FIRST_LINE);
         } else {
-            return loadUnsafeLabel(pm);
+            // Trims the label string to the MAX_SAFE_LABEL_LENGTH. This is to prevent that the
+            // system is overwhelmed by an enormous string returned by the application.
+            return TextUtils.trimToSize(loadUnsafeLabel(pm), MAX_SAFE_LABEL_LENGTH);
         }
     }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index cd02aed..a5cd331 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1053,26 +1053,37 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(value = {
-            RollbackDataPolicy.RESTORE,
-            RollbackDataPolicy.WIPE,
-            RollbackDataPolicy.RETAIN
+    @IntDef(prefix = { "ROLLBACK_DATA_POLICY_" }, value = {
+            ROLLBACK_DATA_POLICY_RESTORE,
+            ROLLBACK_DATA_POLICY_WIPE,
+            ROLLBACK_DATA_POLICY_RETAIN
     })
-    public @interface RollbackDataPolicy {
-        /**
-         * User data will be backed up during install and restored during rollback.
-         */
-        int RESTORE = 0;
-        /**
-         * User data won't be backed up during install but will be wiped out during rollback.
-         */
-        int WIPE = 1;
-        /**
-         * User data won't be backed up during install and won't be restored during rollback.
-         * TODO: Not implemented yet.
-         */
-        int RETAIN = 2;
-    }
+    public @interface RollbackDataPolicy {}
+
+    /**
+     * User data will be backed up during install and restored during rollback.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROLLBACK_DATA_POLICY_RESTORE = 0;
+
+    /**
+     * User data won't be backed up during install but will be wiped out during rollback.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROLLBACK_DATA_POLICY_WIPE = 1;
+
+    /**
+     * User data won't be backed up during install and won't be restored during rollback.
+     * TODO: Not implemented yet.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ROLLBACK_DATA_POLICY_RETAIN = 2;
 
     /** @hide */
     @IntDef(flag = true, prefix = { "INSTALL_" }, value = {
@@ -9096,7 +9107,6 @@
     private static final class ApplicationInfoQuery {
         final String packageName;
         final int flags;
-        @UserIdInt
         final int userId;
 
         ApplicationInfoQuery(@Nullable String packageName, int flags, int userId) {
@@ -9158,10 +9168,6 @@
                             query.packageName, query.flags, query.userId);
                 }
                 @Override
-                protected boolean bypass(ApplicationInfoQuery query) {
-                    return query.userId < 0;
-                }
-                @Override
                 protected ApplicationInfo maybeCheckConsistency(
                         ApplicationInfoQuery query, ApplicationInfo proposedResult) {
                     // Implementing this debug check for ApplicationInfo would require a
@@ -9172,7 +9178,7 @@
 
     /** @hide */
     public static ApplicationInfo getApplicationInfoAsUserCached(
-            String packageName, int flags, @UserIdInt int userId) {
+            String packageName, int flags, int userId) {
         return sApplicationInfoCache.query(
                 new ApplicationInfoQuery(packageName, flags, userId));
     }
@@ -9204,7 +9210,6 @@
     private static final class PackageInfoQuery {
         final String packageName;
         final int flags;
-        @UserIdInt
         final int userId;
 
         PackageInfoQuery(@Nullable String packageName, int flags, int userId) {
@@ -9265,10 +9270,6 @@
                             query.packageName, query.flags, query.userId);
                 }
                 @Override
-                protected boolean bypass(PackageInfoQuery query) {
-                    return query.userId < 0;
-                }
-                @Override
                 protected PackageInfo maybeCheckConsistency(
                         PackageInfoQuery query, PackageInfo proposedResult) {
                     // Implementing this debug check for PackageInfo would require a
@@ -9279,7 +9280,7 @@
 
     /** @hide */
     public static PackageInfo getPackageInfoAsUserCached(
-            String packageName, int flags, @UserIdInt int userId) {
+            String packageName, int flags, int userId) {
         return sPackageInfoCache.query(new PackageInfoQuery(packageName, flags, userId));
     }
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bed0383..29ce397 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -55,6 +55,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.split.SplitAssetLoader;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.ApkAssets;
@@ -7425,7 +7427,7 @@
             mCompileSdkVersionCodename = dest.readString();
             mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
 
-            mKeySetMapping = readKeySetMapping(dest);
+            mKeySetMapping = ParsingPackageUtils.readKeySetMapping(dest);
 
             cpuAbiOverride = dest.readString();
             use32bitAbi = (dest.readInt() == 1);
@@ -7551,73 +7553,13 @@
             dest.writeInt(mCompileSdkVersion);
             dest.writeString(mCompileSdkVersionCodename);
             dest.writeArraySet(mUpgradeKeySets);
-            writeKeySetMapping(dest, mKeySetMapping);
+            ParsingPackageUtils.writeKeySetMapping(dest, mKeySetMapping);
             dest.writeString(cpuAbiOverride);
             dest.writeInt(use32bitAbi ? 1 : 0);
             dest.writeByteArray(restrictUpdateHash);
             dest.writeInt(visibleToInstantApps ? 1 : 0);
         }
 
-        /**
-         * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
-         */
-        private static void writeKeySetMapping(
-                Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
-            if (keySetMapping == null) {
-                dest.writeInt(-1);
-                return;
-            }
-
-            final int N = keySetMapping.size();
-            dest.writeInt(N);
-
-            for (int i = 0; i < N; i++) {
-                dest.writeString(keySetMapping.keyAt(i));
-                ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
-                if (keys == null) {
-                    dest.writeInt(-1);
-                    continue;
-                }
-
-                final int M = keys.size();
-                dest.writeInt(M);
-                for (int j = 0; j < M; j++) {
-                    dest.writeSerializable(keys.valueAt(j));
-                }
-            }
-        }
-
-        /**
-         * Reads a keyset mapping from the given parcel at the given data position. May return
-         * {@code null} if the serialized mapping was {@code null}.
-         */
-        private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
-            final int N = in.readInt();
-            if (N == -1) {
-                return null;
-            }
-
-            ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
-            for (int i = 0; i < N; ++i) {
-                String key = in.readString();
-                final int M = in.readInt();
-                if (M == -1) {
-                    keySetMapping.put(key, null);
-                    continue;
-                }
-
-                ArraySet<PublicKey> keys = new ArraySet<>(M);
-                for (int j = 0; j < M; ++j) {
-                    PublicKey pk = (PublicKey) in.readSerializable();
-                    keys.add(pk);
-                }
-
-                keySetMapping.put(key, keys);
-            }
-
-            return keySetMapping;
-        }
-
         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
             public Package createFromParcel(Parcel in) {
                 return new Package(in);
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 01c0a88..f727a48 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,6 +18,8 @@
 
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 import static android.content.pm.parsing.ParsingPackageUtils.validateName;
 import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
 import static android.content.pm.parsing.ParsingUtils.DEFAULT_MIN_SDK_VERSION;
@@ -27,7 +29,6 @@
 import android.annotation.NonNull;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 import android.content.pm.parsing.result.ParseInput;
@@ -78,8 +79,6 @@
      * This performs validity checking on cluster style packages, such as
      * requiring identical package name and version codes, a single base APK,
      * and unique split names.
-     *
-     * @see PackageParser#parsePackage(File, int)
      */
     public static ParseResult<PackageLite> parsePackageLite(ParseInput input,
             File packageFile, int flags) {
@@ -506,7 +505,7 @@
         }
 
         // Check to see if overlay should be excluded based on system property condition
-        if (!PackageParser.checkRequiredSystemProperties(requiredSystemPropertyName,
+        if (!checkRequiredSystemProperties(requiredSystemPropertyName,
                 requiredSystemPropertyValue)) {
             Slog.i(TAG, "Skipping target and overlay pair " + targetPackage + " and "
                     + codePath + ": overlay ignored due to required system property: "
@@ -577,7 +576,7 @@
             return null;
         }
 
-        final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey);
+        final PublicKey publicKey = parsePublicKey(encodedPublicKey);
         if (publicKey == null) {
             Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
             return null;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 9fee7bb..f2a6a5c 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -535,7 +535,7 @@
         ai.setMaxAspectRatio(maxAspectRatio != null ? maxAspectRatio : 0f);
         Float minAspectRatio = a.getMinAspectRatio();
         ai.setMinAspectRatio(minAspectRatio != null ? minAspectRatio : 0f);
-        ai.supportsSizeChanges = a.getSupportsSizeChanges();
+        ai.supportsSizeChanges = a.isSupportsSizeChanges();
         ai.requestedVrComponent = a.getRequestedVrComponent();
         ai.rotationAnimation = a.getRotationAnimation();
         ai.colorMode = a.getColorMode();
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 72cc929..d6e1ac9 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -360,7 +360,7 @@
 
     ParsingPackage setCompileSdkVersion(int compileSdkVersion);
 
-    ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
+    ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName);
 
     ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible);
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 0db6546..f0d95d9 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -553,7 +553,7 @@
 
             setCompileSdkVersion(manifestArray.getInteger(
                     R.styleable.AndroidManifest_compileSdkVersion, 0));
-            setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+            setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString(
                     R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
 
             setIsolatedSplitLoading(manifestArray.getBoolean(
@@ -2686,8 +2686,8 @@
     }
 
     @Override
-    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
-        this.compileSdkVersionCodeName = compileSdkVersionCodename;
+    public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) {
+        this.compileSdkVersionCodeName = compileSdkVersionCodeName;
         return this;
     }
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index fc4aa5e..809a544 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -47,7 +47,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
 import android.content.pm.Signature;
 import android.content.pm.SigningDetails;
 import android.content.pm.parsing.component.ComponentParseUtils;
@@ -91,6 +90,7 @@
 import android.os.FileUtils;
 import android.os.Parcel;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.ext.SdkExtensions;
@@ -99,6 +99,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Pair;
 import android.util.Slog;
@@ -122,7 +123,12 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -330,8 +336,6 @@
      * result from a previous parse of the same {@code packageFile} with the same
      * {@code flags}. Note that this method does not check whether {@code packageFile}
      * has changed since the last parse, it's up to callers to do so.
-     *
-     * @see PackageParser#parsePackageLite(File, int)
      */
     public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
         if (packageFile.isDirectory()) {
@@ -1069,7 +1073,7 @@
                                     + " must define a public-key value on first use at "
                                     + parser.getPositionDescription());
                         } else if (encodedKey != null) {
-                            PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
+                            PublicKey currentKey = parsePublicKey(encodedKey);
                             if (currentKey == null) {
                                 Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
                                         + parser.getPositionDescription() + " key-set "
@@ -1613,8 +1617,39 @@
     }
 
     /**
-     * {@link ParseResult} version of
-     * {@link PackageParser#computeMinSdkVersion(int, String, int, String[], String[])}
+     * Computes the minSdkVersion to use at runtime. If the package is not
+     * compatible with this platform, populates {@code outError[0]} with an
+     * error message.
+     * <p>
+     * If {@code minCode} is not specified, e.g. the value is {@code null},
+     * then behavior varies based on the {@code platformSdkVersion}:
+     * <ul>
+     * <li>If the platform SDK version is greater than or equal to the
+     * {@code minVers}, returns the {@code mniVers} unmodified.
+     * <li>Otherwise, returns -1 to indicate that the package is not
+     * compatible with this platform.
+     * </ul>
+     * <p>
+     * Otherwise, the behavior varies based on whether the current platform
+     * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+     * has length > 0:
+     * <ul>
+     * <li>If this is a pre-release platform and the value specified by
+     * {@code targetCode} is contained within the array of allowed pre-release
+     * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+     * <li>If this is a released platform, this method will return -1 to
+     * indicate that the package is not compatible with this platform.
+     * </ul>
+     *
+     * @param minVers minSdkVersion number, if specified in the application
+     *                manifest, or 1 otherwise
+     * @param minCode minSdkVersion code, if specified in the application
+     *                manifest, or {@code null} otherwise
+     * @param platformSdkVersion platform SDK version number, typically
+     *                           Build.VERSION.SDK_INT
+     * @param platformSdkCodenames array of allowed prerelease SDK codenames
+     *                             for this platform
+     * @return the minSdkVersion to use at runtime if successful
      */
     public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
             @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
@@ -1651,8 +1686,31 @@
     }
 
     /**
-     * {@link ParseResult} version of
-     * {@link PackageParser#computeTargetSdkVersion(int, String, String[], String[])}
+     * Computes the targetSdkVersion to use at runtime. If the package is not
+     * compatible with this platform, populates {@code outError[0]} with an
+     * error message.
+     * <p>
+     * If {@code targetCode} is not specified, e.g. the value is {@code null},
+     * then the {@code targetVers} will be returned unmodified.
+     * <p>
+     * Otherwise, the behavior varies based on whether the current platform
+     * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+     * has length > 0:
+     * <ul>
+     * <li>If this is a pre-release platform and the value specified by
+     * {@code targetCode} is contained within the array of allowed pre-release
+     * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+     * <li>If this is a released platform, this method will return -1 to
+     * indicate that the package is not compatible with this platform.
+     * </ul>
+     *
+     * @param targetVers targetSdkVersion number, if specified in the
+     *                   application manifest, or 0 otherwise
+     * @param targetCode targetSdkVersion code, if specified in the application
+     *                   manifest, or {@code null} otherwise
+     * @param platformSdkCodenames array of allowed pre-release SDK codenames
+     *                             for this platform
+     * @return the targetSdkVersion to use at runtime if successful
      */
     public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
             @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
@@ -2684,7 +2742,7 @@
                     R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
             String propValue = sa.getString(
                     R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
-            if (!PackageParser.checkRequiredSystemProperties(propName, propValue)) {
+            if (!checkRequiredSystemProperties(propName, propValue)) {
                 String message = "Skipping target and overlay pair " + target + " and "
                         + pkg.getBaseApkPath()
                         + ": overlay ignored due to required system property: "
@@ -2962,6 +3020,114 @@
     }
 
     /**
+     * @return {@link PublicKey} of a given encoded public key.
+     */
+    public static final PublicKey parsePublicKey(final String encodedPublicKey) {
+        if (encodedPublicKey == null) {
+            Slog.w(TAG, "Could not parse null public key");
+            return null;
+        }
+
+        try {
+            return parsePublicKey(Base64.decode(encodedPublicKey, Base64.DEFAULT));
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+            return null;
+        }
+    }
+
+    /**
+     * @return {@link PublicKey} of the given byte array of a public key.
+     */
+    public static final PublicKey parsePublicKey(final byte[] publicKey) {
+        if (publicKey == null) {
+            Slog.w(TAG, "Could not parse null public key");
+            return null;
+        }
+
+        final EncodedKeySpec keySpec;
+        try {
+            keySpec = new X509EncodedKeySpec(publicKey);
+        } catch (IllegalArgumentException e) {
+            Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+            return null;
+        }
+
+        /* First try the key as an RSA key. */
+        try {
+            final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+            return keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
+        } catch (InvalidKeySpecException e) {
+            // Not a RSA public key.
+        }
+
+        /* Now try it as a ECDSA key. */
+        try {
+            final KeyFactory keyFactory = KeyFactory.getInstance("EC");
+            return keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
+        } catch (InvalidKeySpecException e) {
+            // Not a ECDSA public key.
+        }
+
+        /* Now try it as a DSA key. */
+        try {
+            final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+            return keyFactory.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
+        } catch (InvalidKeySpecException e) {
+            // Not a DSA public key.
+        }
+
+        /* Not a supported key type */
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if both the property name and value are empty or if the given system
+     * property is set to the specified value. Properties can be one or more, and if properties are
+     * more than one, they must be separated by comma, and count of names and values must be equal,
+     * and also every given system property must be set to the corresponding value.
+     * In all other cases, returns {@code false}
+     */
+    public static boolean checkRequiredSystemProperties(@Nullable String rawPropNames,
+            @Nullable String rawPropValues) {
+        if (TextUtils.isEmpty(rawPropNames) || TextUtils.isEmpty(rawPropValues)) {
+            if (!TextUtils.isEmpty(rawPropNames) || !TextUtils.isEmpty(rawPropValues)) {
+                // malformed condition - incomplete
+                Slog.w(TAG, "Disabling overlay - incomplete property :'" + rawPropNames
+                        + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+                        + " AND requiredSystemPropertyValue to be specified.");
+                return false;
+            }
+            // no valid condition set - so no exclusion criteria, overlay will be included.
+            return true;
+        }
+
+        final String[] propNames = rawPropNames.split(",");
+        final String[] propValues = rawPropValues.split(",");
+
+        if (propNames.length != propValues.length) {
+            Slog.w(TAG, "Disabling overlay - property :'" + rawPropNames
+                    + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+                    + " AND requiredSystemPropertyValue lists to have the same size.");
+            return false;
+        }
+        for (int i = 0; i < propNames.length; i++) {
+            // Check property value: make sure it is both set and equal to expected value
+            final String currValue = SystemProperties.get(propNames[i]);
+            if (!TextUtils.equals(currValue, propValues[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Collect certificates from all the APKs described in the given package. Also asserts that
      * all APK contents are signed correctly and consistently.
      *
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 07ec6a8..289716a 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -16,9 +16,10 @@
 
 package android.content.pm.parsing;
 
+import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.res.XmlResourceParser;
@@ -62,7 +63,7 @@
     @NonNull
     public static ParseResult unknownTag(String parentTag, ParsingPackage pkg,
             XmlResourceParser parser, ParseInput input) throws IOException, XmlPullParserException {
-        if (PackageParser.RIGID_PARSER) {
+        if (RIGID_PARSER) {
             return input.error("Bad element under " + parentTag + ": " + parser.getName());
         }
         Slog.w(TAG, "Unknown element under " + parentTag + ": "
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 73ee132..adb6b76 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -23,6 +23,7 @@
 import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityTaskManager;
 import android.content.ComponentName;
@@ -423,6 +424,7 @@
         }
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
         @Override
         public ParsedActivity createFromParcel(Parcel source) {
@@ -513,10 +515,6 @@
         return minAspectRatio;
     }
 
-    public boolean getSupportsSizeChanges() {
-        return supportsSizeChanges;
-    }
-
     @Nullable
     public String getRequestedVrComponent() {
         return requestedVrComponent;
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java
index 3c0f097..838adfd 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponent.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java
@@ -43,8 +43,8 @@
 /** @hide */
 public abstract class ParsedComponent implements Parcelable {
 
-    private static ParsedIntentInfo.ListParceler sForIntentInfos = Parcelling.Cache.getOrCreate(
-            ParsedIntentInfo.ListParceler.class);
+    private static final ParsedIntentInfo.ListParceler sForIntentInfos =
+            Parcelling.Cache.getOrCreate(ParsedIntentInfo.ListParceler.class);
 
     @NonNull
     @DataClass.ParcelWith(ForInternedString.class)
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
index 65ff472..4178920 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
+++ b/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.os.Parcel;
@@ -94,6 +95,7 @@
         this.functionalTest = in.readByte() != 0;
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedInstrumentation> CREATOR =
             new Parcelable.Creator<ParsedInstrumentation>() {
                 @Override
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
index 01ee0f4..59d4a95 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm.parsing.component;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.IntentFilter;
 import android.os.Parcel;
@@ -58,6 +59,7 @@
             item.writeIntentInfoToParcel(dest, parcelFlags);
         }
 
+        @NonNull
         @Override
         public ParsedIntentInfo unparcel(Parcel source) {
             return new ParsedIntentInfo(source);
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
index dd71fa4..668b9cc 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
@@ -16,10 +16,11 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+
 import android.annotation.NonNull;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageParser;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingUtils;
@@ -97,8 +98,7 @@
             String nodeName = parser.getName();
             switch (nodeName) {
                 case "action": {
-                    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
-                            "name");
+                    String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
                     if (value == null) {
                         result = input.error("No value supplied for <android:name>");
                     } else if (value.isEmpty()) {
@@ -113,8 +113,7 @@
                     break;
                 }
                 case "category": {
-                    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
-                            "name");
+                    String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
                     if (value == null) {
                         result = input.error("No value supplied for <android:name>");
                     } else if (value.isEmpty()) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/core/java/android/content/pm/parsing/component/ParsedPermission.java
index 50bc3d9..0f82941 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermission.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermission.java
@@ -16,6 +16,7 @@
 
 package android.content.pm.parsing.component;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PermissionInfo;
 import android.os.Parcel;
@@ -167,6 +168,7 @@
         this.knownCerts = sForStringSet.unparcel(in);
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedPermission> CREATOR =
             new Parcelable.Creator<ParsedPermission>() {
                 @Override
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java
index c39d6b1..fe10225 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcess.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java
@@ -19,7 +19,6 @@
 import static java.util.Collections.emptySet;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/core/java/android/content/pm/parsing/component/ParsedProvider.java
index ebf85f7..9a12b48 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProvider.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProvider.java
@@ -169,6 +169,7 @@
         this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
         @Override
         public ParsedProvider createFromParcel(Parcel source) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
index 0b03567..c4b8b98 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -16,10 +16,10 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
 import static android.content.pm.parsing.component.ComponentParseUtils.flag;
 
 import android.annotation.NonNull;
-import android.content.pm.PackageParser;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.pm.parsing.ParsingPackage;
@@ -262,7 +262,7 @@
                 }
                 provider.setGrantUriPermissions(true);
             } else {
-                if (PackageParser.RIGID_PARSER) {
+                if (RIGID_PARSER) {
                     return input.error("No path, pathPrefix, or pathPattern for <path-permission>");
                 }
 
@@ -308,7 +308,7 @@
             }
 
             if (!havePerm) {
-                if (PackageParser.RIGID_PARSER) {
+                if (RIGID_PARSER) {
                     return input.error(
                             "No readPermission or writePermission for <path-permission>");
                 }
@@ -365,7 +365,7 @@
                     provider.setPathPermissions(newp);
                 }
             } else {
-                if (PackageParser.RIGID_PARSER) {
+                if (RIGID_PARSER) {
                     return input.error(
                             "No path, pathPrefix, or pathPattern for <path-permission>");
                 }
diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/content/pm/parsing/component/ParsedService.java
index 471d346..5499a13 100644
--- a/core/java/android/content/pm/parsing/component/ParsedService.java
+++ b/core/java/android/content/pm/parsing/component/ParsedService.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.os.Parcel;
@@ -83,6 +84,7 @@
         this.permission = sForInternedString.unparcel(in);
     }
 
+    @NonNull
     public static final Parcelable.Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
         @Override
         public ParsedService createFromParcel(Parcel source) {
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 2b9a17a..a0c3f75 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -115,8 +115,8 @@
 
     @Override
     public AssetManager getSplitAssetManager(int idx) throws IllegalArgumentException {
-        // Since we insert the base at position 0, and PackageParser keeps splits separate from
-        // the base, we need to adjust the index.
+        // Since we insert the base at position 0, and ParsingPackageUtils keeps splits separate
+        // from the base, we need to adjust the index.
         loadDependenciesForSplit(idx + 1);
         return mCachedAssetManagers[idx + 1];
     }
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 0140280..8df7c37 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -180,7 +180,7 @@
             @NonNull List<Integer> pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
             boolean isApex, boolean isApkInApex, @NonNull List<Integer> snapshottedUsers) {
         this(packageRolledBackFrom, packageRolledBackTo, pendingBackups, pendingRestores, isApex,
-                isApkInApex, snapshottedUsers, PackageManager.RollbackDataPolicy.RESTORE);
+                isApkInApex, snapshottedUsers, PackageManager.ROLLBACK_DATA_POLICY_RESTORE);
     }
 
     /** @hide */
@@ -207,7 +207,7 @@
         this.mPendingRestores = null;
         this.mPendingBackups = null;
         this.mSnapshottedUsers = null;
-        this.mRollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
+        this.mRollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
     }
 
     @Override
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/core/java/android/debug/FingerprintAndPairDevice.aidl
similarity index 72%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to core/java/android/debug/FingerprintAndPairDevice.aidl
index c7c2ad8..b439e14 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/core/java/android/debug/FingerprintAndPairDevice.aidl
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package android.debug;
 
-parcelable InputConnectionCommand;
+import android.debug.PairDevice;
+
+/**
+ * @see {@link android.debug.IAdbManager#getPairedDevices()}
+ * @hide
+ */
+parcelable FingerprintAndPairDevice {
+    String keyFingerprint;
+    PairDevice device;
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/core/java/android/debug/IAdbCallback.aidl
similarity index 63%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to core/java/android/debug/IAdbCallback.aidl
index c7c2ad8..9c8f1cf 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/core/java/android/debug/IAdbCallback.aidl
@@ -14,6 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package android.debug;
 
-parcelable InputConnectionCommand;
+import android.debug.AdbTransportType;
+
+/**
+ * Callback interface of {@link android.debug.IAdbCallbackManager}.
+ *
+ * @hide
+ */
+oneway interface IAdbCallback {
+    /**
+     * On debugging enabled, service providing IAdbManager calls this function.
+     */
+    void onDebuggingChanged(boolean enabled, AdbTransportType type);
+}
diff --git a/core/java/android/debug/IAdbManager.aidl b/core/java/android/debug/IAdbManager.aidl
index aea7633..314c405 100644
--- a/core/java/android/debug/IAdbManager.aidl
+++ b/core/java/android/debug/IAdbManager.aidl
@@ -16,6 +16,9 @@
 
 package android.debug;
 
+import android.debug.FingerprintAndPairDevice;
+import android.debug.IAdbCallback;
+
 /**
  * Interface to communicate remotely with the {@code AdbService} in the system server.
  *
@@ -58,9 +61,10 @@
     void denyWirelessDebugging();
 
     /**
-     * Returns a Map<String, PairDevice> with the key fingerprint mapped to the device information.
+     * Returns an array of NamedPairDevice with the key fingerprint mapped to the device
+     * information.
      */
-    Map getPairedDevices();
+    FingerprintAndPairDevice[] getPairedDevices();
 
     /**
      * Unpair the device identified by the key fingerprint it uses.
@@ -108,4 +112,14 @@
      * QR code.
      */
     boolean isAdbWifiQrSupported();
+
+    /**
+     * Register callback for ADB debugging changed notification.
+     */
+    void registerCallback(IAdbCallback callback);
+
+    /**
+     * Unregister callback for ADB debugging changed notification.
+     */
+    void unregisterCallback(IAdbCallback callback);
 }
diff --git a/core/java/android/debug/PairDevice.aidl b/core/java/android/debug/PairDevice.aidl
new file mode 100644
index 0000000..c72a5ed
--- /dev/null
+++ b/core/java/android/debug/PairDevice.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.debug;
+
+/**
+ * Contains information about the client in an ADB connection.
+ * @see {@link android.debug.IAdbManager#getPairedDevices()}
+ * @hide
+ */
+parcelable PairDevice {
+    /**
+     * The human-readable name of the device.
+     */
+    String name;
+
+    /**
+     * The device's guid.
+     */
+    String guid;
+
+    /**
+     * Indicates whether the device is currently connected to adbd.
+     */
+    boolean connected;
+}
\ No newline at end of file
diff --git a/core/java/android/debug/PairDevice.java b/core/java/android/debug/PairDevice.java
deleted file mode 100644
index 2d5b446..0000000
--- a/core/java/android/debug/PairDevice.java
+++ /dev/null
@@ -1,112 +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 android.debug;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.Immutable;
-import com.android.internal.util.Preconditions;
-
-/**
- * Contains information about the client in an ADB connection.
- * @hide
- */
-@Immutable
-public class PairDevice implements Parcelable {
-    /**
-     * The human-readable name of the device.
-     */
-    @NonNull private final String mName;
-
-    /**
-     * The device's guid.
-     */
-    @NonNull private final String mGuid;
-
-    /**
-     * Indicates whether the device is currently connected to adbd.
-     */
-    private final boolean mConnected;
-
-    public PairDevice(@NonNull String name, @NonNull String guid, boolean connected) {
-        Preconditions.checkStringNotEmpty(name);
-        Preconditions.checkStringNotEmpty(guid);
-        mName = name;
-        mGuid = guid;
-        mConnected = connected;
-    }
-
-    /**
-     * @return the device name.
-     */
-    @NonNull
-    public String getDeviceName() {
-        return mName;
-    }
-
-    /**
-     * @return the device GUID.
-     */
-    @NonNull
-    public String getGuid() {
-        return mGuid;
-    }
-
-    /**
-     * @return the adb connection state of the device.
-     */
-    public boolean isConnected() {
-        return mConnected;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(mName);
-        dest.writeString(mGuid);
-        dest.writeBoolean(mConnected);
-    }
-
-    /**
-     * @return Human-readable info about the object.
-     */
-    @Override
-    public String toString() {
-        return "\n" + mName + "\n" + mGuid + "\n" + mConnected;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @NonNull
-    public static final Parcelable.Creator<PairDevice> CREATOR =
-            new Creator<PairDevice>() {
-                @Override
-                public PairDevice createFromParcel(Parcel source) {
-                    return new PairDevice(source.readString(), source.readString(),
-                            source.readBoolean());
-                }
-
-                @Override
-                public PairDevice[] newArray(int size) {
-                    return new PairDevice[size];
-                }
-            };
-}
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index d69a9e1..5571165 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -52,4 +52,6 @@
     void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
 
     void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+
+    void showSensorUseDialog(int sensor);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 4526ab77..3c524b2 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -24,15 +24,16 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.service.SensorPrivacyIndividualEnabledSensorProto;
 import android.service.SensorPrivacyToggleSourceProto;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 
@@ -48,6 +49,8 @@
 @SystemService(Context.SENSOR_PRIVACY_SERVICE)
 public final class SensorPrivacyManager {
 
+    private static final String LOG_TAG = SensorPrivacyManager.class.getSimpleName();
+
     /**
      * Unique Id of this manager to identify to the service
      * @hide
@@ -379,7 +382,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
     public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
-        return isSensorPrivacyEnabled(sensor, getCurrentUserId());
+        return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
     }
 
     /**
@@ -410,7 +413,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
             boolean enable) {
-        setSensorPrivacy(source, sensor, enable, getCurrentUserId());
+        setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT);
     }
 
     /**
@@ -446,7 +449,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
             @Sensors.Sensor int sensor, boolean enable) {
-        setSensorPrivacyForProfileGroup(source , sensor, enable, getCurrentUserId());
+        setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT);
     }
 
     /**
@@ -481,7 +484,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void suppressSensorPrivacyReminders(int sensor,
             boolean suppress) {
-        suppressSensorPrivacyReminders(sensor, suppress, getCurrentUserId());
+        suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT);
     }
 
     /**
@@ -505,6 +508,25 @@
     }
 
     /**
+     * If sensor privacy for the provided sensor is enabled then this call will show the user the
+     * dialog which is shown when an application attempts to use that sensor. If privacy isn't
+     * enabled then this does nothing.
+     *
+     * This call can only be made by the system uid.
+     *
+     * @throws SecurityException when called by someone other than system uid.
+     *
+     * @hide
+     */
+    public void showSensorUseDialog(int sensor) {
+        try {
+            mService.showSensorUseDialog(sensor);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Received exception while trying to show sensor use dialog", e);
+        }
+    }
+
+    /**
      * A class implementing this interface can register with the {@link
      * android.hardware.SensorPrivacyManager} to receive notification when the all-sensor privacy
      * state changes.
@@ -609,12 +631,4 @@
         }
     }
 
-    private int getCurrentUserId() {
-        try {
-            return ActivityManager.getService().getCurrentUserId();
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-        return 0;
-    }
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c78dd53..b55a1cb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2318,6 +2318,51 @@
             new Key<Float>("android.control.zoomRatio", float.class);
 
     /**
+     * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+     * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+     * set to MAXIMUM_RESOLUTION.</p>
+     * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+     * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AF_REGIONS
+     * @see CaptureRequest#SENSOR_PIXEL_MODE
+     * @hide
+     */
+    public static final Key<Boolean> CONTROL_AF_REGIONS_SET =
+            new Key<Boolean>("android.control.afRegionsSet", boolean.class);
+
+    /**
+     * <p>Framework-only private key which informs camera fwk that the AE regions has been set
+     * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+     * set to MAXIMUM_RESOLUTION.</p>
+     * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+     * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     * @see CaptureRequest#SENSOR_PIXEL_MODE
+     * @hide
+     */
+    public static final Key<Boolean> CONTROL_AE_REGIONS_SET =
+            new Key<Boolean>("android.control.aeRegionsSet", boolean.class);
+
+    /**
+     * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+     * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+     * set to MAXIMUM_RESOLUTION.</p>
+     * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+     * {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_REGIONS
+     * @see CaptureRequest#SENSOR_PIXEL_MODE
+     * @hide
+     */
+    public static final Key<Boolean> CONTROL_AWB_REGIONS_SET =
+            new Key<Boolean>("android.control.awbRegionsSet", boolean.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -3057,6 +3102,21 @@
             new Key<Integer>("android.scaler.rotateAndCrop", int.class);
 
     /**
+     * <p>Framework-only private key which informs camera fwk that the scaler crop region
+     * ({@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}) has been set by the client and it need
+     * not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to MAXIMUM_RESOLUTION.</p>
+     * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#SCALER_CROP_REGION
+     * @see CaptureRequest#SENSOR_PIXEL_MODE
+     * @hide
+     */
+    public static final Key<Boolean> SCALER_CROP_REGION_SET =
+            new Key<Boolean>("android.scaler.cropRegionSet", boolean.class);
+
+    /**
      * <p>Duration each pixel is exposed to
      * light.</p>
      * <p>If the sensor can't expose this exact duration, it will shorten the
diff --git a/core/java/android/hardware/camera2/MultiResolutionImageReader.java b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
index 3af1b5b..0dbf29d 100644
--- a/core/java/android/hardware/camera2/MultiResolutionImageReader.java
+++ b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
@@ -91,7 +91,7 @@
      * </p>
      * <p>
      * The {@code maxImages} parameter determines the maximum number of
-     * {@link Image} objects that can be be acquired from each of the {@code ImageReader}
+     * {@link Image} objects that can be acquired from each of the {@code ImageReader}
      * within the {@code MultiResolutionImageReader}. However, requesting more buffers will
      * use up more memory, so it is important to use only the minimum number necessary. The
      * application is strongly recommended to acquire no more than {@code maxImages} images
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index bfc1f27..02245e4 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -446,7 +446,9 @@
         }
     }
 
-    public void release() {
+    public void release(boolean skipCloseNotification) {
+        boolean notifyClose = false;
+
         synchronized (mInterfaceLock) {
             mHandlerThread.quitSafely();
 
@@ -463,6 +465,7 @@
             if (mExtensionClientId >= 0) {
                 CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
                 if (mInitialized) {
+                    notifyClose = true;
                     CameraExtensionCharacteristics.releaseSession();
                 }
             }
@@ -476,6 +479,16 @@
             mClientRepeatingRequestSurface = null;
             mClientCaptureSurface = null;
         }
+
+        if (notifyClose && !skipCloseNotification) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallbacks.onClosed(
+                        CameraAdvancedExtensionSessionImpl.this));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     private void notifyConfigurationFailure() {
@@ -485,7 +498,7 @@
             }
         }
 
-        release();
+        release(true /*skipCloseNotification*/);
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -501,15 +514,7 @@
             android.hardware.camera2.CameraCaptureSession.StateCallback {
         @Override
         public void onClosed(@NonNull CameraCaptureSession session) {
-            release();
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> mCallbacks.onClosed(
-                       CameraAdvancedExtensionSessionImpl.this));
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            release(false /*skipCloseNotification*/);
         }
 
         @Override
@@ -812,6 +817,8 @@
                     Log.e(TAG,"Failed to parcel buffer fence!");
                 }
             }
+            parcelImage.width = img.getWidth();
+            parcelImage.height = img.getHeight();
             parcelImage.format = img.getFormat();
             parcelImage.timestamp = img.getTimestamp();
             parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 11b137ca..fc728a2 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -696,6 +696,16 @@
                 mCurrentSession.replaceSessionClose();
             }
 
+            if (mCurrentExtensionSession != null) {
+                mCurrentExtensionSession.release(false /*skipCloseNotification*/);
+                mCurrentExtensionSession = null;
+            }
+
+            if (mCurrentAdvancedExtensionSession != null) {
+                mCurrentAdvancedExtensionSession.release(false /*skipCloseNotification*/);
+                mCurrentAdvancedExtensionSession = null;
+            }
+
             // TODO: dont block for this
             boolean configureSuccess = true;
             CameraAccessException pendingException = null;
@@ -1342,12 +1352,12 @@
             }
 
             if (mCurrentExtensionSession != null) {
-                mCurrentExtensionSession.release();
+                mCurrentExtensionSession.release(true /*skipCloseNotification*/);
                 mCurrentExtensionSession = null;
             }
 
             if (mCurrentAdvancedExtensionSession != null) {
-                mCurrentAdvancedExtensionSession.release();
+                mCurrentAdvancedExtensionSession.release(true /*skipCloseNotification*/);
                 mCurrentAdvancedExtensionSession = null;
             }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 537b894..ecd2491 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -49,8 +49,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IInterface;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.annotation.NonNull;
@@ -265,13 +263,6 @@
             } catch (ClassCastException e) {
                 throw new UnsupportedOperationException("Failed casting preview processor!");
             }
-            if (mClientRepeatingRequestSurface != null) {
-                mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
-                        nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
-                mRepeatingRequestImageWriter = ImageWriter.newInstance(
-                        mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
-                        CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
-            }
             mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
                     repeatingSurfaceInfo.mHeight,
                     CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -285,11 +276,6 @@
             mPreviewRequestUpdateProcessor.onImageFormatUpdate(
                     CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
         } else {
-            if (mClientRepeatingRequestSurface != null) {
-                mRepeatingRequestImageWriter = ImageWriter.newInstance(
-                        mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
-                        CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
-            }
             mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
                     repeatingSurfaceInfo.mHeight,
                     CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -320,7 +306,6 @@
                 mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth,
                         surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
                         mImageExtender.getMaxCaptureStage());
-                mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
             } else {
                 // The client doesn't intend to trigger multi-frame capture, however the
                 // image extender still needs to get initialized and the camera still capture
@@ -367,6 +352,29 @@
         }
     }
 
+    private void finishPipelineInitialization() throws RemoteException {
+        if (mClientRepeatingRequestSurface != null) {
+            if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
+                mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
+                        nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
+                mRepeatingRequestImageWriter = ImageWriter.newInstance(
+                        mClientRepeatingRequestSurface,
+                        PREVIEW_QUEUE_SIZE,
+                        CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+            } else if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_NONE) {
+                mRepeatingRequestImageWriter = ImageWriter.newInstance(
+                        mClientRepeatingRequestSurface,
+                        PREVIEW_QUEUE_SIZE,
+                        CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+            }
+        }
+        if ((mImageProcessor != null) && (mClientCaptureSurface != null)) {
+            CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(
+                    mClientCaptureSurface);
+            mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
+        }
+    }
+
     /**
      * @hide
      */
@@ -623,7 +631,9 @@
     }
 
     /** @hide */
-    public void release() {
+    public void release(boolean skipCloseNotification) {
+        boolean notifyClose = false;
+
         synchronized (mInterfaceLock) {
             mInternalRepeatingRequestEnabled = false;
             mHandlerThread.quitSafely();
@@ -639,6 +649,7 @@
             if (mExtensionClientId >= 0) {
                 CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
                 if (mInitialized) {
+                    notifyClose = true;
                     CameraExtensionCharacteristics.releaseSession();
                 }
             }
@@ -689,6 +700,15 @@
             mCameraRepeatingSurface = mClientRepeatingRequestSurface = null;
             mCameraBurstSurface = mClientCaptureSurface = null;
         }
+
+        if (notifyClose && !skipCloseNotification) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallbacks.onClosed(CameraExtensionSessionImpl.this));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     private void notifyConfigurationFailure() {
@@ -698,7 +718,7 @@
             }
         }
 
-        release();
+        release(true /*skipCloseNotification*/);
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -730,14 +750,7 @@
             android.hardware.camera2.CameraCaptureSession.StateCallback {
         @Override
         public void onClosed(@NonNull CameraCaptureSession session) {
-            release();
-
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> mCallbacks.onClosed(CameraExtensionSessionImpl.this));
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            release(false /*skipCloseNotification*/);
         }
 
         @Override
@@ -750,6 +763,7 @@
             synchronized (mInterfaceLock) {
                 mCaptureSession = session;
                 try {
+                    finishPipelineInitialization();
                     CameraExtensionCharacteristics.initializeSession(mInitializeHandler);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to initialize session! Extension service does"
@@ -1640,6 +1654,8 @@
                 Log.e(TAG,"Failed to parcel buffer fence!");
             }
         }
+        parcelImage.width = img.getWidth();
+        parcelImage.height = img.getHeight();
         parcelImage.format = img.getFormat();
         parcelImage.timestamp = img.getTimestamp();
         parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 950d716b..afefcbe 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
-import android.hardware.HardwareBuffer;
 import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
@@ -76,43 +75,22 @@
         ImageWriter writer = null;
         Image img = null;
         SurfaceInfo surfaceInfo = new SurfaceInfo();
-        int nativeFormat = SurfaceUtils.getSurfaceFormat(s);
+        int nativeFormat = SurfaceUtils.detectSurfaceFormat(s);
         int dataspace = SurfaceUtils.getSurfaceDataspace(s);
+        Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
+        surfaceInfo.mFormat = nativeFormat;
+        surfaceInfo.mWidth = surfaceSize.getWidth();
+        surfaceInfo.mHeight = surfaceSize.getHeight();
+        surfaceInfo.mUsage = SurfaceUtils.getSurfaceUsage(s);
         // Jpeg surfaces cannot be queried for their usage and other parameters
         // in the usual way below. A buffer can only be de-queued after the
         // producer overrides the surface dimensions to (width*height) x 1.
         if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) &&
                 (dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) {
             surfaceInfo.mFormat = ImageFormat.JPEG;
-            Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
-            surfaceInfo.mWidth = surfaceSize.getWidth();
-            surfaceInfo.mHeight = surfaceSize.getHeight();
             return surfaceInfo;
         }
 
-        HardwareBuffer buffer = null;
-        try {
-            writer = ImageWriter.newInstance(s, 1);
-            img = writer.dequeueInputImage();
-            buffer = img.getHardwareBuffer();
-            surfaceInfo.mFormat = buffer.getFormat();
-            surfaceInfo.mWidth = buffer.getWidth();
-            surfaceInfo.mHeight = buffer.getHeight();
-            surfaceInfo.mUsage = buffer.getUsage();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to query surface, returning defaults!");
-        } finally {
-            if (buffer != null) {
-                buffer.close();
-            }
-            if (img != null) {
-                img.close();
-            }
-            if (writer != null) {
-                writer.close();
-            }
-        }
-
         return surfaceInfo;
     }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 6cbe107..196134b 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -53,6 +53,7 @@
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.MandatoryStreamCombination;
 import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
 import android.hardware.camera2.params.OisSample;
@@ -1708,6 +1709,34 @@
                 metadata.setGpsLocation((Location) value);
             }
         });
+        sSetCommandMap.put(CaptureRequest.SCALER_CROP_REGION.getNativeKey(),
+                new SetCommand() {
+            @Override
+            public <T> void setValue(CameraMetadataNative metadata, T value) {
+                metadata.setScalerCropRegion((Rect) value);
+            }
+        });
+        sSetCommandMap.put(CaptureRequest.CONTROL_AWB_REGIONS.getNativeKey(),
+                new SetCommand() {
+            @Override
+            public <T> void setValue(CameraMetadataNative metadata, T value) {
+                metadata.setAWBRegions(value);
+            }
+        });
+        sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
+                new SetCommand() {
+            @Override
+            public <T> void setValue(CameraMetadataNative metadata, T value) {
+                metadata.setAFRegions(value);
+            }
+        });
+        sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
+                new SetCommand() {
+            @Override
+            public <T> void setValue(CameraMetadataNative metadata, T value) {
+                metadata.setAERegions(value);
+            }
+        });
     }
 
     private boolean setAvailableFormats(int[] value) {
@@ -1777,6 +1806,45 @@
         return true;
     }
 
+    private <T> boolean setScalerCropRegion(Rect cropRegion) {
+        if (cropRegion == null) {
+            return false;
+        }
+        setBase(CaptureRequest.SCALER_CROP_REGION_SET, true);
+        setBase(CaptureRequest.SCALER_CROP_REGION, cropRegion);
+        return true;
+    }
+
+    private <T> boolean setAFRegions(T afRegions) {
+        if (afRegions == null) {
+            return false;
+        }
+        setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
+        // The cast to CaptureRequest.Key is needed since java does not support template
+        // specialization and we need to route this method to
+        // setBase(CaptureRequest.Key<T> key, T value)
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+        return true;
+    }
+
+    private <T> boolean setAERegions(T aeRegions) {
+        if (aeRegions == null) {
+            return false;
+        }
+        setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+        return true;
+    }
+
+    private <T> boolean setAWBRegions(T awbRegions) {
+        if (awbRegions == null) {
+            return false;
+        }
+        setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+        return true;
+    }
+
     private void updateNativeAllocation() {
         long currentBufferSize = nativeGetBufferSize(mMetadataPtr);
 
diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java
index 8dfc0a7b..70c85a1 100644
--- a/core/java/android/hardware/camera2/params/InputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/InputConfiguration.java
@@ -42,7 +42,7 @@
     private final boolean mIsMultiResolution;
 
     /**
-     * Create an input configration with the width, height, and user-defined format.
+     * Create an input configuration with the width, height, and user-defined format.
      *
      * <p>Images of a user-defined format are accessible by applications. Use
      * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
@@ -64,7 +64,7 @@
     }
 
     /**
-     * Create an input configration with the format and a list of multi-resolution input stream
+     * Create an input configuration with the format and a list of multi-resolution input stream
      * info.
      *
      * <p>Use {@link
@@ -108,7 +108,7 @@
     }
 
     /**
-     * Get the width of this input configration.
+     * Get the width of this input configuration.
      *
      * @return width of this input configuration.
      */
@@ -117,7 +117,7 @@
     }
 
     /**
-     * Get the height of this input configration.
+     * Get the height of this input configuration.
      *
      * @return height of this input configuration.
      */
@@ -126,7 +126,7 @@
     }
 
     /**
-     * Get the format of this input configration.
+     * Get the format of this input configuration.
      *
      * @return format of this input configuration.
      */
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 35b5c15..fd1a331 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -105,6 +105,20 @@
     }
 
     /**
+     * Get the surface usage bits.
+     *
+     * @param surface The surface to be queried for usage.
+     * @return the native object id of the surface, 0 if surface is not backed by a native object.
+     */
+    public static long getSurfaceUsage(Surface surface) {
+        checkNotNull(surface);
+        try {
+            return nativeDetectSurfaceUsageFlags(surface);
+        } catch (IllegalArgumentException e) {
+            return 0;
+        }
+    }
+    /**
      * Get the Surface size.
      *
      * @param surface The surface to be queried for size.
@@ -146,6 +160,23 @@
     }
 
     /**
+     * Detect and retrieve the Surface format without any
+     * additional overrides.
+     *
+     * @param surface The surface to be queried for format.
+     * @return format of the surface.
+     *
+     * @throws IllegalArgumentException if the surface is already abandoned.
+     */
+    public static int detectSurfaceFormat(Surface surface) {
+        checkNotNull(surface);
+        int surfaceType = nativeDetectSurfaceType(surface);
+        if (surfaceType == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned");
+
+        return surfaceType;
+    }
+
+    /**
      * Get the Surface dataspace.
      *
      * @param surface The surface to be queried for dataspace.
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index abcc33c..4f20553 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -21,6 +21,7 @@
 import android.graphics.Point;
 import android.hardware.SensorManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.PowerManager;
 import android.util.IntArray;
 import android.util.Slog;
@@ -340,6 +341,28 @@
     public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);
 
     /**
+     * Returns the window token of the level of the WindowManager hierarchy to mirror. Returns null
+     * if layer mirroring by SurfaceFlinger should not be performed for the given displayId.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract IBinder getWindowTokenClientToMirror(int displayId);
+
+    /**
+     * For the given displayId, updates the window token of the level of the WindowManager hierarchy
+     * to mirror. If windowToken is null, then SurfaceFlinger performs no layer mirroring to the
+     * given display.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract void setWindowTokenClientToMirror(int displayId, IBinder windowToken);
+
+    /**
+     * Returns the default size of the surface associated with the display, or null if the surface
+     * is not provided for layer mirroring by SurfaceFlinger.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract Point getDisplaySurfaceDefaultSize(int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 71688c7c..0e86f43 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.media.projection.MediaProjection;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.Surface;
@@ -91,9 +92,16 @@
      */
     private int mDisplayIdToMirror = DEFAULT_DISPLAY;
 
+    /**
+     * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+     * should not be performed.
+     */
+    @Nullable
+    private IBinder mWindowTokenClientToMirror = null;
 
 
-    // Code below generated by codegen v1.0.20.
+
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -115,7 +123,8 @@
             int flags,
             @Nullable Surface surface,
             @Nullable String uniqueId,
-            int displayIdToMirror) {
+            int displayIdToMirror,
+            @Nullable IBinder windowTokenClientToMirror) {
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mName);
@@ -135,6 +144,7 @@
         this.mSurface = surface;
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
+        this.mWindowTokenClientToMirror = windowTokenClientToMirror;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -212,6 +222,15 @@
         return mDisplayIdToMirror;
     }
 
+    /**
+     * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+     * should not be performed.
+     */
+    @DataClass.Generated.Member
+    public @Nullable IBinder getWindowTokenClientToMirror() {
+        return mWindowTokenClientToMirror;
+    }
+
     @Override
     @DataClass.Generated.Member
     public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -221,6 +240,7 @@
         int flg = 0;
         if (mSurface != null) flg |= 0x20;
         if (mUniqueId != null) flg |= 0x40;
+        if (mWindowTokenClientToMirror != null) flg |= 0x100;
         dest.writeInt(flg);
         dest.writeString(mName);
         dest.writeInt(mWidth);
@@ -230,6 +250,7 @@
         if (mSurface != null) dest.writeTypedObject(mSurface, flags);
         if (mUniqueId != null) dest.writeString(mUniqueId);
         dest.writeInt(mDisplayIdToMirror);
+        if (mWindowTokenClientToMirror != null) dest.writeStrongBinder(mWindowTokenClientToMirror);
     }
 
     @Override
@@ -252,6 +273,7 @@
         Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
         String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
         int displayIdToMirror = in.readInt();
+        IBinder windowTokenClientToMirror = (flg & 0x100) == 0 ? null : (IBinder) in.readStrongBinder();
 
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
@@ -272,6 +294,7 @@
         this.mSurface = surface;
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
+        this.mWindowTokenClientToMirror = windowTokenClientToMirror;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -305,6 +328,7 @@
         private @Nullable Surface mSurface;
         private @Nullable String mUniqueId;
         private int mDisplayIdToMirror;
+        private @Nullable IBinder mWindowTokenClientToMirror;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -439,10 +463,22 @@
             return this;
         }
 
+        /**
+         * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+         * should not be performed.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setWindowTokenClientToMirror(@NonNull IBinder value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mWindowTokenClientToMirror = value;
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull VirtualDisplayConfig build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100; // Mark builder used
+            mBuilderFieldsSet |= 0x200; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mFlags = 0;
@@ -456,6 +492,9 @@
             if ((mBuilderFieldsSet & 0x80) == 0) {
                 mDisplayIdToMirror = DEFAULT_DISPLAY;
             }
+            if ((mBuilderFieldsSet & 0x100) == 0) {
+                mWindowTokenClientToMirror = null;
+            }
             VirtualDisplayConfig o = new VirtualDisplayConfig(
                     mName,
                     mWidth,
@@ -464,12 +503,13 @@
                     mFlags,
                     mSurface,
                     mUniqueId,
-                    mDisplayIdToMirror);
+                    mDisplayIdToMirror,
+                    mWindowTokenClientToMirror);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x100) != 0) {
+            if ((mBuilderFieldsSet & 0x200) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -477,10 +517,10 @@
     }
 
     @DataClass.Generated(
-            time = 1604456298440L,
-            codegenVersion = "1.0.20",
+            time = 1620657851981L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate  int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate  int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 5a8687d..ec5bcf1 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -43,6 +43,16 @@
 
 import java.lang.ref.WeakReference;
 
+/**
+ * Takes care of remote method invocations of {@link InputConnection} in the IME side.
+ *
+ * <p>This class works as a proxy to forward API calls on {@link InputConnection} to
+ * {@link com.android.internal.inputmethod.RemoteInputConnectionImpl} running on the IME client
+ * (editor app) process then waits replies as needed.</p>
+ *
+ * <p>See also {@link IInputContext} for the actual {@link android.os.Binder} IPC protocols under
+ * the hood.</p>
+ */
 final class RemoteInputConnection implements InputConnection {
     private static final String TAG = "RemoteInputConnection";
 
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 2afbe8b..3d18125 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -570,6 +570,9 @@
             }
         }
 
+        final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
+                AppOpsManager.pauseNotedAppOpsCollection();
+
         if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
             flags |= FLAG_COLLECT_NOTED_APP_OPS;
         }
@@ -577,6 +580,8 @@
         try {
             return transactNative(code, data, reply, flags);
         } finally {
+            AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
+
             if (transactListener != null) {
                 transactListener.onTransactEnded(session);
             }
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index f38271a..403f55c 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.os.IDropBoxManagerService;
 
+import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.File;
@@ -257,7 +258,8 @@
             } else {
                 return null;
             }
-            return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
+            return (mFlags & IS_GZIPPED) != 0
+                ? new GZIPInputStream(new BufferedInputStream(is)) : is;
         }
 
         public static final @android.annotation.NonNull Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f3e0ce9..edfcb3d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1460,17 +1460,17 @@
     /** {@hide} */
     @VisibleForTesting
     public static ParcelFileDescriptor convertToModernFd(FileDescriptor fd) {
-        try {
-            Context context = AppGlobals.getInitialApplication();
-            if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
-                // Never convert modern fd for MediaProvider, because this requires
-                // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
-                return null;
-            }
-            return MediaStore.getOriginalMediaFormatFileDescriptor(context,
-                    ParcelFileDescriptor.dup(fd));
+        Context context = AppGlobals.getInitialApplication();
+        if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
+            // Never convert modern fd for MediaProvider, because this requires
+            // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
+            return null;
+        }
+
+        try (ParcelFileDescriptor dupFd = ParcelFileDescriptor.dup(fd)) {
+            return MediaStore.getOriginalMediaFormatFileDescriptor(context, dupFd);
         } catch (Exception e) {
-            Log.d(TAG, "Failed to convert to modern format file descriptor", e);
+            // Ignore error
             return null;
         }
     }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3aa0bcb..2f66a39 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2092,9 +2092,7 @@
      * when light idle mode restrictions are being actively applied; it will return false if the
      * device is in a long-term idle mode but currently running a maintenance window where
      * restrictions have been lifted.
-     * @hide
      */
-    @UnsupportedAppUsage
     public boolean isLightDeviceIdleMode() {
         try {
             return mService.isLightDeviceIdleMode();
@@ -2555,9 +2553,7 @@
     /**
      * Intent that is broadcast when the state of {@link #isLightDeviceIdleMode()} changes.
      * This broadcast is only sent to registered receivers.
-     * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
             = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6bca336..9f37c48 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -34,12 +34,9 @@
 
 import libcore.io.IoUtils;
 
-import java.io.BufferedReader;
 import java.io.FileDescriptor;
-import java.io.FileReader;
 import java.io.IOException;
 import java.util.Map;
-import java.util.StringTokenizer;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -1472,43 +1469,4 @@
     }
 
     private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
-
-    /**
-     * Checks if a process corresponding to a specific pid owns any file locks.
-     * @param pid The process ID for which we want to know the existence of file locks.
-     * @return true If the process holds any file locks, false otherwise.
-     * @throws IOException if /proc/locks can't be accessed.
-     *
-     * @hide
-     */
-    public static boolean hasFileLocks(int pid) throws Exception {
-        BufferedReader br = null;
-
-        try {
-            br = new BufferedReader(new FileReader("/proc/locks"));
-            String line;
-
-            while ((line = br.readLine()) != null) {
-                StringTokenizer st = new StringTokenizer(line);
-
-                for (int i = 0; i < 5 && st.hasMoreTokens(); i++) {
-                    String str = st.nextToken();
-                    try {
-                        if (i == 4 && Integer.parseInt(str) == pid) {
-                            return true;
-                        }
-                    } catch (NumberFormatException nfe) {
-                        throw new Exception("Exception parsing /proc/locks at \" "
-                                + line +  " \", token #" + i);
-                    }
-                }
-            }
-
-            return false;
-        } finally {
-            if (br != null) {
-                br.close();
-            }
-        }
-    }
 }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 9ab6955..4a94c32 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -16,7 +16,7 @@
 
 package android.permission;
 
-import android.content.AttributionSource;
+import android.content.AttributionSourceState;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
@@ -87,7 +87,7 @@
 
     boolean isAutoRevokeExempted(String packageName, int userId);
 
-    void registerAttributionSource(in AttributionSource source);
+    void registerAttributionSource(in AttributionSourceState source);
 
-    boolean isRegisteredAttributionSource(in AttributionSource source);
+    boolean isRegisteredAttributionSource(in AttributionSourceState source);
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index a52ede8..4cd9fb9 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1177,7 +1177,7 @@
         // enforcement we need to replace the binder with a unique one.
         final AttributionSource registeredSource = source.withToken(new Binder());
         try {
-            mPermissionManager.registerAttributionSource(registeredSource);
+            mPermissionManager.registerAttributionSource(registeredSource.asState());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -1196,7 +1196,7 @@
      */
     public boolean isRegisteredAttributionSource(@NonNull AttributionSource source) {
         try {
-            return mPermissionManager.isRegisteredAttributionSource(source);
+            return mPermissionManager.isRegisteredAttributionSource(source.asState());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -1315,6 +1315,7 @@
     private static final class PackageNamePermissionQuery {
         final String permName;
         final String pkgName;
+        @UserIdInt
         final int userId;
 
         PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName,
@@ -1374,6 +1375,10 @@
                     return checkPackageNamePermissionUncached(
                             query.permName, query.pkgName, query.userId);
                 }
+                @Override
+                protected boolean bypass(PackageNamePermissionQuery query) {
+                    return query.userId < 0;
+                }
             };
 
     /**
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 03f94c5..19f204b 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -31,7 +31,9 @@
 import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
 import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
 import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 
@@ -63,7 +65,8 @@
  *
  * @hide
  */
-public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener {
+public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener,
+        AppOpsManager.OnOpStartedListener {
 
     /** Whether to show the mic and camera icons.  */
     private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled";
@@ -160,9 +163,10 @@
         mUserContexts = new ArrayMap<>();
         mUserContexts.put(Process.myUserHandle(), mContext);
         // TODO ntmyren: make this listen for flag enable/disable changes
-        String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
-        mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops,
-                context.getMainExecutor(), this);
+        String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
+        mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this);
+        int[] ops = { OP_CAMERA, OP_RECORD_AUDIO };
+        mAppOpsManager.startWatchingStarted(ops, this);
     }
 
     private Context getUserContext(UserHandle user) {
@@ -182,25 +186,65 @@
     public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
             @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags,
             int attributionChainId) {
-        if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
-                || attributionFlags == ATTRIBUTION_FLAGS_NONE
-                || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
-            // If this is not a chain, or it is untrusted, return
+        if (active) {
+            // Started callback handles these
             return;
         }
 
-        if (!active) {
-            // if any link in the chain is finished, remove the chain.
-            // TODO ntmyren: be smarter about this
-            mAttributionChains.remove(attributionChainId);
+        // if any link in the chain is finished, remove the chain. Then, find any other chains that
+        // contain this op/package/uid/tag combination, and remove them, as well.
+        // TODO ntmyren: be smarter about this
+        mAttributionChains.remove(attributionChainId);
+        int numChains = mAttributionChains.size();
+        ArrayList<Integer> toRemove = new ArrayList<>();
+        for (int i = 0; i < numChains; i++) {
+            int chainId = mAttributionChains.keyAt(i);
+            ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i);
+            int chainSize = chain.size();
+            for (int j = 0; j < chainSize; j++) {
+                AccessChainLink link = chain.get(j);
+                if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) {
+                    toRemove.add(chainId);
+                    break;
+                }
+            }
+        }
+        mAttributionChains.removeAll(toRemove);
+    }
+
+    @Override
+    public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
+       // not part of an attribution chain. Do nothing
+    }
+
+    @Override
+    public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+            @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result,
+            @StartedType int startedType, @AttributionFlags int attributionFlags,
+            int attributionChainId) {
+        if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
+                || attributionFlags == ATTRIBUTION_FLAGS_NONE
+                || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
+            // If this is not a successful start, or it is not a chain, or it is untrusted, return
             return;
         }
+        addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid,
+                attributionTag, attributionFlags, attributionChainId);
+    }
+
+    private void addLinkToChainIfNotPresent(String op, String packageName, int uid,
+            String attributionTag, int attributionFlags, int attributionChainId) {
 
         ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent(
                 attributionChainId, k -> new ArrayList<>());
         AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid,
                 attributionFlags);
 
+        if (currentChain.contains(link)) {
+            return;
+        }
+
         int currSize = currentChain.size();
         if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) {
             // if the list is empty, this link is the end, or the last link in the current chain
@@ -613,5 +657,21 @@
         public boolean isStart() {
             return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0;
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof AccessChainLink)) {
+                return false;
+            }
+            AccessChainLink other = (AccessChainLink) obj;
+            return other.flags == flags && packageAndOpEquals(other.usage.op,
+                    other.usage.packageName, other.usage.attributionTag, other.usage.uid);
+        }
+
+        public boolean packageAndOpEquals(String op, String packageName, String attributionTag,
+                int uid) {
+            return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName)
+                    && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid;
+        }
     }
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b3d60a5..570d73d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8588,6 +8588,15 @@
          * Type: INTEGER
          */
         public static final String UNGROUPED_WITH_PHONES = "summ_phones";
+
+        /**
+         * Flag indicating if the account is the default account for new contacts. At most one
+         * account has this flag set at a time. It can only be set to 1 on a row with null data set.
+         * <p>
+         * Type: INTEGER (boolean)
+         * @hide
+         */
+        String IS_DEFAULT = "x_is_default";
     }
 
     /**
@@ -8681,6 +8690,13 @@
          * The MIME-type of {@link #CONTENT_URI} providing a single setting.
          */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
+
+        /**
+         * Action used to launch the UI to set the default account for new contacts.
+         */
+        @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+        public static final String ACTION_SET_DEFAULT_ACCOUNT =
+                "android.provider.action.SET_DEFAULT_ACCOUNT";
     }
 
     /**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index ded598a..ef486a9 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -258,6 +258,14 @@
     public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
 
     /**
+     * Namespace for all lmkd related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
+
+    /**
      * Namespace for all location related features.
      *
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f75dd88..7a031e3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10165,6 +10165,61 @@
         @Readable
         public static final String GAME_DASHBOARD_ALWAYS_ON = "game_dashboard_always_on";
 
+
+        /**
+         * For this device state, no specific auto-rotation lock setting should be applied.
+         * If the user toggles the auto-rotate lock in this state, the setting will apply to the
+         * previously valid device state.
+         * @hide
+         */
+        public static final int DEVICE_STATE_ROTATION_LOCK_IGNORED = 0;
+        /**
+         * For this device state, the setting for auto-rotation is locked.
+         * @hide
+         */
+        public static final int DEVICE_STATE_ROTATION_LOCK_LOCKED = 1;
+        /**
+         * For this device state, the setting for auto-rotation is unlocked.
+         * @hide
+         */
+        public static final int DEVICE_STATE_ROTATION_LOCK_UNLOCKED = 2;
+
+        /**
+         * The different settings that can be used as values with
+         * {@link #DEVICE_STATE_ROTATION_LOCK}.
+         * @hide
+         */
+        @IntDef(prefix = {"DEVICE_STATE_ROTATION_LOCK_"}, value = {
+                DEVICE_STATE_ROTATION_LOCK_IGNORED,
+                DEVICE_STATE_ROTATION_LOCK_LOCKED,
+                DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface DeviceStateRotationLockSetting {
+        }
+
+        /**
+         * Rotation lock setting keyed on device state.
+         *
+         * This holds a serialized map using int keys that represent Device States and value of
+         * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
+         * device state.
+         *
+         * Serialized as key0:value0:key1:value1:...:keyN:valueN.
+         *
+         * Example: "0:1:1:2:2:1"
+         * This example represents a map of:
+         * <ul>
+         *     <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+         *     <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+         *     <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+         * </ul>
+         *
+         * @hide
+         */
+        public static final String DEVICE_STATE_ROTATION_LOCK =
+                "device_state_rotation_lock";
+
         /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
@@ -13441,6 +13496,69 @@
                 = "forced_app_standby_for_small_battery_enabled";
 
         /**
+         * Whether to enable the TARE subsystem as a whole or not.
+         * 1 means enable, 0 means disable.
+         *
+         * @hide
+         */
+        public static final String ENABLE_TARE = "enable_tare";
+
+        /**
+         * Default value for {@link #ENABLE_TARE}.
+         *
+         * @hide
+         */
+        public static final int DEFAULT_ENABLE_TARE = 0;
+
+        /**
+         * Whether to enable the TARE AlarmManager economic policy or not.
+         * 1 means enable, 0 means disable.
+         *
+         * @hide
+         */
+        public static final String ENABLE_TARE_ALARM_MANAGER = "enable_tare_alarm_manager";
+
+        /**
+         * Default value for {@link #ENABLE_TARE_ALARM_MANAGER}.
+         *
+         * @hide
+         */
+        public static final int DEFAULT_ENABLE_TARE_ALARM_MANAGER = 0;
+
+        /**
+         * Settings for AlarmManager's TARE EconomicPolicy (list of its economic factors).
+         *
+         * Keys are listed in {@link android.app.tare.EconomyManager}.
+         *
+         * @hide
+         */
+        public static final String TARE_ALARM_MANAGER_CONSTANTS = "tare_alarm_manager_constants";
+
+        /**
+         * Whether to enable the TARE JobScheduler economic policy or not.
+         * 1 means enable, 0 means disable.
+         *
+         * @hide
+         */
+        public static final String ENABLE_TARE_JOB_SCHEDULER = "enable_tare_job_scheduler";
+
+        /**
+         * Default value for {@link #ENABLE_TARE_JOB_SCHEDULER}.
+         *
+         * @hide
+         */
+        public static final int DEFAULT_ENABLE_TARE_JOB_SCHEDULER = 0;
+
+        /**
+         * Settings for JobScheduler's TARE EconomicPolicy (list of its economic factors).
+         *
+         * Keys are listed in {@link android.app.tare.EconomyManager}.
+         *
+         * @hide
+         */
+        public static final String TARE_JOB_SCHEDULER_CONSTANTS = "tare_job_scheduler_constants";
+
+        /**
          * Whether or not to enable the User Absent, Radios Off feature on small battery devices.
          * Type: int (0 for false, 1 for true)
          * Default: 0
@@ -16307,18 +16425,19 @@
             public static final int RETAIL_MODE_RETAIL = 1;
 
             /**
-             * The play store availability.
+             * The play store availability on companion phone.
              * @hide
              */
-            public static final String PLAY_STORE_AVAILABILITY = "play_store_availability";
+            public static final String PHONE_PLAY_STORE_AVAILABILITY =
+                    "phone_play_store_availability";
 
-            // Possible play store availability states
+            // Possible phone play store availability states
             /** @hide */
-            public static final int PLAY_STORE_AVAILABILITY_UNKNOWN = 0;
+            public static final int PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN = 0;
             /** @hide */
-            public static final int PLAY_STORE_AVAILABLE = 1;
+            public static final int PHONE_PLAY_STORE_AVAILABLE = 1;
             /** @hide */
-            public static final int PLAY_STORE_UNAVAILABLE = 2;
+            public static final int PHONE_PLAY_STORE_UNAVAILABLE = 2;
 
             /**
              * Whether the bug report is enabled.
@@ -16720,6 +16839,62 @@
              * @hide
              */
             public static final String UNGAZE_ENABLED = "ungaze_enabled";
+
+            /**
+             * The device's battery saver mode, which can be one of the following:
+             * -{@link BATTERY_SAVER_MODE_NONE}
+             * -{@link BATTERY_SAVER_MODE_LIGHT}
+             * -{@link BATTERY_SAVER_MODE_TRADITIONAL_WATCH}
+             * -{@link BATTERY_SAVER_MODE_TIME_ONLY}
+             * -{@link BATTERY_SAVER_MODE_CUSTOM}
+             * @hide
+             */
+            public static final String BATTERY_SAVER_MODE = "battery_saver_mode";
+
+            /**
+             * Not in Battery Saver Mode
+             * @hide
+             */
+            public static final int BATTERY_SAVER_MODE_NONE = 0;
+            /**
+             * In Lightweight Battery Saver Mode
+             * @hide
+             */
+            public static final int BATTERY_SAVER_MODE_LIGHT = 1;
+            /**
+             * In Traditional Watch Mode Battery Saver Mode
+             * @hide
+             */
+            public static final int BATTERY_SAVER_MODE_TRADITIONAL_WATCH = 2;
+            /**
+             * In Time-only Mode Battery Saver Mode
+             * @hide
+             */
+            public static final int BATTERY_SAVER_MODE_TIME_ONLY = 3;
+            /**
+             * Partner's Battery Saver implementation is being used
+             * @hide
+             */
+            public static final int BATTERY_SAVER_MODE_CUSTOM = 4;
+
+            /**
+             * The maximum ambient mode duration when an activity is allowed to auto resume.
+             * @hide
+             */
+            public static final String WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS =
+                    "wear_activity_auto_resume_timeout_ms";
+
+            /**
+             * If burn in protection is enabled.
+             * @hide
+             */
+            public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection";
+
+            /**
+             * Whether the device has combined location setting enabled.
+             * @hide
+             */
+            public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable";
         }
     }
 
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 4137416..face870 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -783,6 +783,9 @@
      *         This may happen if another detector has been instantiated or the
      *         {@link VoiceInteractionService} hosting this detector has been shut down.
      */
+    // TODO: Remove this RequiresPermission since it isn't actually enforced. Also fix the javadoc
+    // about permissions enforcement (when it throws vs when it just returns false) for other
+    // methods in this class.
     @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
     @Override
     public boolean stopRecognition() {
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 02294e5..f7a3415 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -82,6 +82,9 @@
         try {
             mManagerService.startListeningFromMic(
                     mAudioFormat, new BinderCallback(mHandler, mCallback));
+        } catch (SecurityException e) {
+            Slog.e(TAG, "startRecognition failed: " + e);
+            return false;
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 6a0fec7..f52c9ff 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -520,6 +520,12 @@
             // Ignore.
         }
 
+        try {
+            mSystemService.shutdownHotwordDetectionService();
+        } catch (Exception ex) {
+            // Ignore.
+        }
+
         mSoftwareHotwordDetector = null;
     }
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 1111c28..4bf6049 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -16,6 +16,8 @@
 
 package android.service.wallpaper;
 
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+import static android.app.WallpaperManager.COMMAND_UNFREEZE;
 import static android.graphics.Matrix.MSCALE_X;
 import static android.graphics.Matrix.MSCALE_Y;
 import static android.graphics.Matrix.MSKEW_X;
@@ -42,12 +44,14 @@
 import android.graphics.BLASTBufferQueue;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
+import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Build;
@@ -56,6 +60,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -200,6 +205,12 @@
         boolean mVisible;
         boolean mReportedVisible;
         boolean mDestroyed;
+        // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false
+        // after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once
+        // mScreenshotSurfaceControl isn't null. When this happens, then Engine is notified through
+        // doVisibilityChanged that main wallpaper surface is no longer visible and the wallpaper
+        // host receives onVisibilityChanged(false) callback.
+        private boolean mFrozenRequested = false;
 
         // Current window state.
         boolean mCreated;
@@ -264,6 +275,8 @@
         SurfaceControl mSurfaceControl = new SurfaceControl();
         SurfaceControl mBbqSurfaceControl;
         BLASTBufferQueue mBlastBufferQueue;
+        private SurfaceControl mScreenshotSurfaceControl;
+        private Point mScreenshotSize = new Point();
 
         final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
             {
@@ -776,8 +789,10 @@
                 WallpaperColors color = colors.get(i);
                 RectF area = regions.get(i);
                 if (color == null || area == null) {
-                    Log.wtf(TAG, "notifyLocalColorsChanged null values. color: "
-                            + color + " area " + area);
+                    if (DEBUG) {
+                        Log.e(TAG, "notifyLocalColorsChanged null values. color: "
+                                + color + " area " + area);
+                    }
                     continue;
                 }
                 try {
@@ -1347,11 +1362,15 @@
             if (!mDestroyed) {
                 mVisible = visible;
                 reportVisibility();
-                if (visible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+                if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
             }
         }
 
         void reportVisibility() {
+            if (mScreenshotSurfaceControl != null && mVisible) {
+                if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change");
+                return;
+            }
             if (!mDestroyed) {
                 mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
                 boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
@@ -1368,6 +1387,10 @@
                         updateSurface(true, false, false);
                     }
                     onVisibilityChanged(visible);
+                    if (mReportedVisible && mFrozenRequested) {
+                        if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update");
+                        freeze();
+                    }
                 }
             }
         }
@@ -1828,6 +1851,9 @@
         void doCommand(WallpaperCommand cmd) {
             Bundle result;
             if (!mDestroyed) {
+                if (COMMAND_FREEZE.equals(cmd.action) || COMMAND_UNFREEZE.equals(cmd.action)) {
+                    updateFrozenState(/* frozenRequested= */ !COMMAND_UNFREEZE.equals(cmd.action));
+                }
                 result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z,
                         cmd.extras, cmd.sync);
             } else {
@@ -1842,6 +1868,159 @@
             }
         }
 
+        private void updateFrozenState(boolean frozenRequested) {
+            if (mIWallpaperEngine.mWallpaperManager.getWallpaperInfo() == null
+                    // Procees the unfreeze command in case the wallaper became static while
+                    // being paused.
+                    && frozenRequested) {
+                if (DEBUG) Log.v(TAG, "Ignoring the freeze command for static wallpapers");
+                return;
+            }
+            mFrozenRequested = frozenRequested;
+            boolean isFrozen = mScreenshotSurfaceControl != null;
+            if (mFrozenRequested == isFrozen) {
+                return;
+            }
+            if (mFrozenRequested) {
+                freeze();
+            } else {
+                unfreeze();
+            }
+        }
+
+        private void freeze() {
+            if (!mReportedVisible || mDestroyed) {
+                // Screenshot can't be taken until visibility is reported to the wallpaper host.
+                return;
+            }
+            if (!showScreenshotOfWallpaper()) {
+                return;
+            }
+            // Prevent a wallpaper host from rendering wallpaper behind a screeshot.
+            doVisibilityChanged(false);
+            // Remember that visibility is requested since it's not guaranteed that
+            // mWindow#dispatchAppVisibility will be called when letterboxed application with
+            // wallpaper background transitions to the Home screen.
+            mVisible = true;
+        }
+
+        private void unfreeze() {
+            cleanUpScreenshotSurfaceControl();
+            if (mVisible) {
+                doVisibilityChanged(true);
+            }
+        }
+
+        private void cleanUpScreenshotSurfaceControl() {
+            // TODO(b/194399558): Add crossfade transition.
+            if (mScreenshotSurfaceControl != null) {
+                new SurfaceControl.Transaction()
+                        .remove(mScreenshotSurfaceControl)
+                        .show(mBbqSurfaceControl)
+                        .apply();
+                mScreenshotSurfaceControl = null;
+            }
+        }
+
+        void scaleAndCropScreenshot() {
+            if (mScreenshotSurfaceControl == null) {
+                return;
+            }
+            if (mScreenshotSize.x <= 0 || mScreenshotSize.y <= 0) {
+                Log.w(TAG, "Unexpected screenshot size: " + mScreenshotSize);
+                return;
+            }
+            // Don't scale down and using the same scaling factor for both dimensions to
+            // avoid stretching wallpaper image.
+            float scaleFactor = Math.max(1, Math.max(
+                    ((float) mSurfaceSize.x) / mScreenshotSize.x,
+                    ((float) mSurfaceSize.y) / mScreenshotSize.y));
+            int diffX =  ((int) (mScreenshotSize.x * scaleFactor)) - mSurfaceSize.x;
+            int diffY =  ((int) (mScreenshotSize.y * scaleFactor)) - mSurfaceSize.y;
+            if (DEBUG) {
+                Log.v(TAG, "Adjusting screenshot: scaleFactor=" + scaleFactor
+                        + " diffX=" + diffX + " diffY=" + diffY + " mSurfaceSize=" + mSurfaceSize
+                        + " mScreenshotSize=" + mScreenshotSize);
+            }
+            new SurfaceControl.Transaction()
+                        .setMatrix(
+                                mScreenshotSurfaceControl,
+                                /* dsdx= */ scaleFactor, /* dtdx= */ 0,
+                                /* dtdy= */ 0, /* dsdy= */ scaleFactor)
+                        .setWindowCrop(
+                                mScreenshotSurfaceControl,
+                                new Rect(
+                                        /* left= */ diffX / 2,
+                                        /* top= */ diffY / 2,
+                                        /* right= */ diffX / 2 + mScreenshotSize.x,
+                                        /* bottom= */ diffY / 2 + mScreenshotSize.y))
+                        .setPosition(mScreenshotSurfaceControl, -diffX / 2, -diffY / 2)
+                        .apply();
+        }
+
+        private boolean showScreenshotOfWallpaper() {
+            if (mDestroyed || mSurfaceControl == null || !mSurfaceControl.isValid()) {
+                if (DEBUG) Log.v(TAG, "Failed to screenshot wallpaper: surface isn't valid");
+                return false;
+            }
+
+            final Rect bounds = new Rect(0, 0, mSurfaceSize.x,  mSurfaceSize.y);
+            if (bounds.isEmpty()) {
+                Log.w(TAG, "Failed to screenshot wallpaper: surface bounds are empty");
+                return false;
+            }
+
+            if (mScreenshotSurfaceControl != null) {
+                Log.e(TAG, "Screenshot is unexpectedly not null");
+                // Destroying previous screenshot since it can have different size.
+                cleanUpScreenshotSurfaceControl();
+            }
+
+            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+                    SurfaceControl.captureLayers(
+                            new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+                                    // Needed because SurfaceFlinger#validateScreenshotPermissions
+                                    // uses this parameter to check whether a caller only attempts
+                                    // to screenshot itself when call doesn't come from the system.
+                                    .setUid(Process.myUid())
+                                    .setChildrenOnly(false)
+                                    .setSourceCrop(bounds)
+                                    .build());
+
+            if (screenshotBuffer == null) {
+                Log.w(TAG, "Failed to screenshot wallpaper: screenshotBuffer is null");
+                return false;
+            }
+
+            final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+
+            // TODO(b/194399558): Add crossfade transition.
+            mScreenshotSurfaceControl = new SurfaceControl.Builder()
+                    .setName("Wallpaper snapshot for engine " + this)
+                    .setFormat(hardwareBuffer.getFormat())
+                    .setParent(mSurfaceControl)
+                    .setSecure(screenshotBuffer.containsSecureLayers())
+                    .setCallsite("WallpaperService.Engine.showScreenshotOfWallpaper")
+                    .setBLASTLayer()
+                    .build();
+
+            mScreenshotSize.set(mSurfaceSize.x, mSurfaceSize.y);
+
+            GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(hardwareBuffer);
+
+            t.setBuffer(mScreenshotSurfaceControl, graphicBuffer);
+            t.setColorSpace(mScreenshotSurfaceControl, screenshotBuffer.getColorSpace());
+            // Place on top everything else.
+            t.setLayer(mScreenshotSurfaceControl, Integer.MAX_VALUE);
+            t.show(mScreenshotSurfaceControl);
+            t.hide(mBbqSurfaceControl);
+            t.apply();
+
+            return true;
+        }
+
         void reportSurfaceDestroyed() {
             if (mSurfaceCreated) {
                 mSurfaceCreated = false;
@@ -2164,6 +2343,7 @@
                     final boolean reportDraw = message.arg1 != 0;
                     mEngine.updateSurface(true, false, reportDraw);
                     mEngine.doOffsetsChanged(true);
+                    mEngine.scaleAndCropScreenshot();
                 } break;
                 case MSG_WINDOW_MOVED: {
                     // Do nothing. What does it mean for a Wallpaper to move?
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index f74990a..c7d9b9c 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -209,7 +209,7 @@
         if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
             byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
             verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
-                    verityDigest, apk.length(), signatureInfo);
+                    verityDigest, apk.getChannel().size(), signatureInfo);
         }
 
         return new VerifiedSigner(
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 4d1402a..b07b522 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -211,7 +211,7 @@
         if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
             byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
             verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
-                    verityDigest, apk.length(), signatureInfo);
+                    verityDigest, apk.getChannel().size(), signatureInfo);
         }
 
         return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 7e6175c..6a24de25 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -368,7 +368,7 @@
             SignatureInfo signatureInfo) throws SecurityException {
         try {
             byte[] expectedRootHash = parseVerityDigestAndVerifySourceLength(expectedDigest,
-                    apk.length(), signatureInfo);
+                    apk.getChannel().size(), signatureInfo);
             VerityBuilder.VerityResult verity = VerityBuilder.generateApkVerityTree(apk,
                     signatureInfo, new ByteBufferFactory() {
                         @Override
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index b0a5992..c7c465d 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -90,7 +90,7 @@
             throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
         long signingBlockSize =
                 signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
-        long dataSize = apk.length() - signingBlockSize;
+        long dataSize = apk.getChannel().size() - signingBlockSize;
         int[] levelOffset = calculateVerityLevelOffset(dataSize);
         int merkleTreeSize = levelOffset[levelOffset.length - 1];
 
@@ -108,7 +108,7 @@
             @NonNull SignatureInfo signatureInfo, @NonNull ByteBuffer footerOutput)
             throws IOException {
         footerOutput.order(ByteOrder.LITTLE_ENDIAN);
-        generateApkVerityHeader(footerOutput, apk.length(), DEFAULT_SALT);
+        generateApkVerityHeader(footerOutput, apk.getChannel().size(), DEFAULT_SALT);
         long signingBlockSize =
                 signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
         generateApkVerityExtensions(footerOutput, signatureInfo.apkSigningBlockOffset,
@@ -339,11 +339,11 @@
                 eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
         consumeByChunk(digester,
                 DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField,
-                    apk.length() - offsetAfterEocdCdOffsetField),
+                    apk.getChannel().size() - offsetAfterEocdCdOffsetField),
                 MMAP_REGION_SIZE_BYTES);
 
         // 5. Pad 0s up to the nearest 4096-byte block before hashing.
-        int lastIncompleteChunkSize = (int) (apk.length() % CHUNK_SIZE_BYTES);
+        int lastIncompleteChunkSize = (int) (apk.getChannel().size() % CHUNK_SIZE_BYTES);
         if (lastIncompleteChunkSize != 0) {
             digester.consume(ByteBuffer.allocate(CHUNK_SIZE_BYTES - lastIncompleteChunkSize));
         }
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 9cb0d1f..e7ff978 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1463,10 +1463,10 @@
             return false;
         }
         final Configuration config = mResources.getConfiguration();
-        // TODO(b/179308296) Temporarily exclude Launcher from being given max bounds, by checking
-        // if the caller is the recents component.
+        // TODO(b/179308296) Temporarily - never report max bounds to only Launcher if the feature
+        // is disabled.
         return config != null && !config.windowConfiguration.getMaxBounds().isEmpty()
-                && !isRecentsComponent();
+                && (mDisplayInfo.shouldConstrainMetricsForLauncher || !isRecentsComponent());
     }
 
     /**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index e1a4402..0257e55 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Path;
@@ -873,18 +874,147 @@
     }
 
     /**
+     * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
+     * which is used to get the related cutout configs for that display.
+     *
+     * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
+     * display if there are different type of cutouts on each display.
+     * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
+     * and the system will load the default configs for main built-in display.
+     */
+    private static int getDisplayCutoutConfigIndex(Resources res, String displayUniqueId) {
+        int index = -1;
+        if (displayUniqueId == null || displayUniqueId.isEmpty()) {
+            return index;
+        }
+        final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
+        final int size = ids.length;
+        for (int i = 0; i < size; i++) {
+            if (displayUniqueId.equals(ids[i])) {
+                index = i;
+                break;
+            }
+        }
+        return index;
+    }
+
+    /**
+     * Gets the display cutout by the given display unique id.
+     *
+     * Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static String getDisplayCutoutPath(Resources res, String displayUniqueId) {
+        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
+        if (index >= 0 && index < array.length) {
+            return array[index];
+        }
+        return res.getString(R.string.config_mainBuiltInDisplayCutout);
+    }
+
+    /**
+     * Gets the display cutout approximation rect by the given display unique id.
+     *
+     * Loads the default config {@link R.string#config_mainBuiltInDisplayCutoutRectApproximation} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     */
+    private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
+        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final String[] array = res.getStringArray(
+                R.array.config_displayCutoutApproximationRectArray);
+        if (index >= 0 && index < array.length) {
+            return array[index];
+        }
+        return res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation);
+    }
+
+    /**
+     * Gets whether to mask a built-in display cutout of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default config {@link R.bool#config_maskMainBuiltInDisplayCutout} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
+        boolean maskCutout;
+        if (index >= 0 && index < array.length()) {
+            maskCutout = array.getBoolean(index, false);
+        } else {
+            maskCutout = res.getBoolean(R.bool.config_maskMainBuiltInDisplayCutout);
+        }
+        array.recycle();
+        return maskCutout;
+    }
+
+    /**
+     * Gets whether to fill a built-in display cutout of a display which is determined by the
+     * given display unique id.
+     *
+     * Loads the default config{@link R.bool#config_fillMainBuiltInDisplayCutout} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
+        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
+        boolean fillCutout;
+        if (index >= 0 && index < array.length()) {
+            fillCutout = array.getBoolean(index, false);
+        } else {
+            fillCutout = res.getBoolean(R.bool.config_fillMainBuiltInDisplayCutout);
+        }
+        array.recycle();
+        return fillCutout;
+    }
+
+    /**
+     * Gets the waterfall cutout by the given display unique id.
+     *
+     * Loads the default waterfall dimens if {@link R.array#config_displayUniqueIdArray} is not set.
+     * {@link R.dimen#waterfall_display_left_edge_size},
+     * {@link R.dimen#waterfall_display_top_edge_size},
+     * {@link R.dimen#waterfall_display_right_edge_size},
+     * {@link R.dimen#waterfall_display_bottom_edge_size}
+     */
+    private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
+        Insets insets;
+        final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray);
+        if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) {
+            final int resourceId = array.getResourceId(index, 0);
+            final TypedArray waterfall = res.obtainTypedArray(resourceId);
+            insets = Insets.of(
+                    waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0),
+                    waterfall.getDimensionPixelSize(1 /* waterfall top edge size */, 0),
+                    waterfall.getDimensionPixelSize(2 /* waterfall right edge size */, 0),
+                    waterfall.getDimensionPixelSize(3 /* waterfall bottom edge size */, 0));
+            waterfall.recycle();
+        } else {
+            insets = loadWaterfallInset(res);
+        }
+        array.recycle();
+        return insets;
+    }
+
+    /**
      * Creates the display cutout according to
      * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest
      * rectangle-base approximation of the cutout.
      *
      * @hide
      */
-    public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth,
-            int displayHeight) {
-        return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout),
-                res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation),
+    public static DisplayCutout fromResourcesRectApproximation(Resources res,
+            String displayUniqueId, int displayWidth, int displayHeight) {
+        return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId),
+                getDisplayCutoutApproximationRect(res, displayUniqueId),
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
-                loadWaterfallInset(res)).second;
+                getWaterfallInsets(res, displayUniqueId)).second;
     }
 
     /**
@@ -892,11 +1022,11 @@
      *
      * @hide
      */
-    public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) {
-        return pathAndDisplayCutoutFromSpec(
-                res.getString(R.string.config_mainBuiltInDisplayCutout), null,
+    public static Path pathFromResources(Resources res, String displayUniqueId, int displayWidth,
+            int displayHeight) {
+        return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), null,
                 displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT,
-                loadWaterfallInset(res)).first;
+                getWaterfallInsets(res, displayUniqueId)).first;
     }
 
     /**
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8e5f905..6572510 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -306,6 +306,13 @@
     public float brightnessDefault;
 
     /**
+     * @hide
+     * True if Display#getRealSize and getRealMetrics should be constrained for Launcher, false
+     * otherwise.
+     */
+    public boolean shouldConstrainMetricsForLauncher = false;
+
+    /**
      * The {@link RoundedCorners} if present, otherwise {@code null}.
      */
     @Nullable
@@ -381,7 +388,8 @@
                 && brightnessMinimum == other.brightnessMinimum
                 && brightnessMaximum == other.brightnessMaximum
                 && brightnessDefault == other.brightnessDefault
-                && Objects.equals(roundedCorners, other.roundedCorners);
+                && Objects.equals(roundedCorners, other.roundedCorners)
+                && shouldConstrainMetricsForLauncher == other.shouldConstrainMetricsForLauncher;
     }
 
     @Override
@@ -432,6 +440,7 @@
         brightnessMaximum = other.brightnessMaximum;
         brightnessDefault = other.brightnessDefault;
         roundedCorners = other.roundedCorners;
+        shouldConstrainMetricsForLauncher = other.shouldConstrainMetricsForLauncher;
     }
 
     public void readFromParcel(Parcel source) {
@@ -488,6 +497,7 @@
         for (int i = 0; i < numUserDisabledFormats; i++) {
             userDisabledHdrTypes[i] = source.readInt();
         }
+        shouldConstrainMetricsForLauncher = source.readBoolean();
     }
 
     @Override
@@ -542,6 +552,7 @@
         for (int i = 0; i < userDisabledHdrTypes.length; i++) {
             dest.writeInt(userDisabledHdrTypes[i]);
         }
+        dest.writeBoolean(shouldConstrainMetricsForLauncher);
     }
 
     @Override
@@ -796,6 +807,8 @@
         sb.append(brightnessMaximum);
         sb.append(", brightnessDefault ");
         sb.append(brightnessDefault);
+        sb.append(", shouldConstrainMetricsForLauncher ");
+        sb.append(shouldConstrainMetricsForLauncher);
         sb.append("}");
         return sb.toString();
     }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9ce4122..8c2348c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -875,4 +875,10 @@
      * @see android.window.WindowProviderService#getLaunchedDisplayId
      */
     int getImeDisplayId();
+
+    /**
+     * Control if we should enable task snapshot features on this device.
+     * @hide
+     */
+    void setTaskSnapshotEnabled(boolean enabled);
 }
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 25dda5b..2884d22 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -171,6 +171,16 @@
     }
 
     /**
+     * Called when the display for the window associated with the input channel has entered or
+     * exited touch mode.
+     *
+     * @param isInTouchMode {@code true} if the display showing the window associated with the
+     *                                  input channel entered touch mode.
+     */
+    public void onTouchModeChanged(boolean isInTouchMode) {
+    }
+
+    /**
      * Called when a batched input event is pending.
      *
      * The batched input event will continue to accumulate additional movement
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index cdc099b..bd68401 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -197,6 +197,12 @@
     public ActivityManager.RunningTaskInfo taskInfo;
 
     /**
+     * {@code true} if picture-in-picture permission is granted in {@link android.app.AppOpsManager}
+     */
+    @UnsupportedAppUsage
+    public boolean allowEnterPip;
+
+    /**
      * The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
      * for non-app window.
      */
@@ -206,10 +212,11 @@
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
-            SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo) {
+            SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo,
+            boolean allowEnterPip) {
         this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
                 position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
-                startBounds, taskInfo, INVALID_WINDOW_TYPE);
+                startBounds, taskInfo, allowEnterPip, INVALID_WINDOW_TYPE);
     }
 
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
@@ -217,7 +224,7 @@
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
             SurfaceControl startLeash, Rect startBounds,
-            ActivityManager.RunningTaskInfo taskInfo,
+            ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip,
             @WindowManager.LayoutParams.WindowType int windowType) {
         this.mode = mode;
         this.taskId = taskId;
@@ -235,6 +242,7 @@
         this.startLeash = startLeash;
         this.startBounds = startBounds == null ? null : new Rect(startBounds);
         this.taskInfo = taskInfo;
+        this.allowEnterPip = allowEnterPip;
         this.windowType = windowType;
     }
 
@@ -255,6 +263,7 @@
         startLeash = in.readTypedObject(SurfaceControl.CREATOR);
         startBounds = in.readTypedObject(Rect.CREATOR);
         taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+        allowEnterPip = in.readBoolean();
         windowType = in.readInt();
     }
 
@@ -281,6 +290,7 @@
         dest.writeTypedObject(startLeash, 0 /* flags */);
         dest.writeTypedObject(startBounds, 0 /* flags */);
         dest.writeTypedObject(taskInfo, 0 /* flags */);
+        dest.writeBoolean(allowEnterPip);
         dest.writeInt(windowType);
     }
 
@@ -299,6 +309,7 @@
         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
         pw.print(prefix); pw.print("leash="); pw.println(leash);
         pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo);
+        pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip);
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
     }
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ff2d2eb..aaf53ee 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -29,6 +29,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -408,6 +409,20 @@
     }
 
     /**
+     * Returns the default size of this Surface provided by the consumer of the surface.
+     * Should only be used by the producer of the surface.
+     *
+     * @hide
+     */
+    @NonNull
+    public Point getDefaultSize() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject));
+        }
+    }
+
+    /**
      * Gets a {@link Canvas} for drawing into this surface.
      *
      * After drawing into the provided {@link Canvas}, the caller must
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index c39426d..a4e7a43 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.RenderNode;
@@ -237,15 +238,6 @@
             new SurfaceControl.Transaction();
 
     /**
-     * Transaction that should be used for
-     * {@link RenderNode.PositionUpdateListener#positionChanged(long, int, int, int, int)}
-     * The callback is invoked from a thread pool so it's not thread safe with other render thread
-     * transactions. Keep the transactions for position changed callbacks on its own transaction.
-     */
-    private final SurfaceControl.Transaction mPositionChangedTransaction =
-            new SurfaceControl.Transaction();
-
-    /**
      * A temporary transaction holder that should only be used when applying right away. There
      * should be no assumption about thread safety for this transaction.
      */
@@ -295,7 +287,6 @@
             int defStyleRes, boolean disableBackgroundLayer) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mUseBlastAdapter = useBlastAdapter(context);
-        mRenderNode.addPositionUpdateListener(mPositionListener);
 
         setWillNotDraw(true);
         mDisableBackgroundLayer = disableBackgroundLayer;
@@ -943,6 +934,24 @@
         }
     }
 
+
+    // The position update listener is used to safely share the surface size between render thread
+    // workers and the UI thread. Both threads need to know the surface size to determine the scale.
+    // The parent layer scales the surface size to view size. The child (BBQ) layer scales
+    // the buffer to the surface size. Both scales along with the window crop must be applied
+    // synchronously otherwise we may see flickers.
+    // When the listener is updated, we will get at least a single position update call so we can
+    // guarantee any changes we post will be applied.
+    private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight,
+            @Nullable Transaction geometryTransaction) {
+        if (mPositionListener != null) {
+            mRenderNode.removePositionUpdateListener(mPositionListener);
+        }
+        mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
+                geometryTransaction);
+        mRenderNode.addPositionUpdateListener(mPositionListener);
+    }
+
     private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
             boolean creating, boolean sizeChanged, boolean hintChanged) {
         boolean realSizeChanged = false;
@@ -985,13 +994,13 @@
             // While creating the surface, we will set it's initial
             // geometry. Outside of that though, we should generally
             // leave it to the RenderThread.
-            //
-            // There is one more case when the buffer size changes we aren't yet
-            // prepared to sync (as even following the transaction applying
-            // we still need to latch a buffer).
-            // b/28866173
-            if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
-                onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+            Transaction geometryTransaction = new Transaction();
+            geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+            if ((sizeChanged || hintChanged) && !creating) {
+                setBufferSize(geometryTransaction);
+            }
+            if (sizeChanged || creating || !isHardwareAccelerated()) {
+                onSetSurfacePositionAndScaleRT(geometryTransaction, mSurfaceControl,
                         mScreenRect.left, /*positionLeft*/
                         mScreenRect.top /*positionTop*/ ,
                         mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
@@ -1002,17 +1011,31 @@
                 // use SCALING_MODE_SCALE and submit a larger size than the surface
                 // size.
                 if (mClipSurfaceToBounds && mClipBounds != null) {
-                    mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+                    geometryTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
                 } else {
-                    mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+                    geometryTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
                             mSurfaceHeight);
                 }
-            }
-            mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
-            if ((sizeChanged || hintChanged) && !creating) {
-                setBufferSize(mTmpTransaction);
-            }
 
+                boolean applyChangesOnRenderThread =
+                        sizeChanged && !creating && isHardwareAccelerated();
+                if (isHardwareAccelerated()) {
+                    // This will consume the passed in transaction and the transaction will be
+                    // applied on a render worker thread.
+                    replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight,
+                            applyChangesOnRenderThread ? geometryTransaction : null);
+                }
+                if (DEBUG_POSITION) {
+                    Log.d(TAG, String.format(
+                            "%d updateSurfacePosition %s"
+                                + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+                            System.identityHashCode(this),
+                            applyChangesOnRenderThread ? "RenderWorker" : "UiThread",
+                            mScreenRect.left, mScreenRect.top, mScreenRect.right,
+                            mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
+                }
+            }
+            mTmpTransaction.merge(geometryTransaction);
             mTmpTransaction.apply();
             updateEmbeddedAccessibilityMatrix();
 
@@ -1242,7 +1265,7 @@
             mBlastSurfaceControl.setTransformHint(mTransformHint);
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
-                        mFormat);
+                        mFormat, transaction);
             }
         } else {
             transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
@@ -1399,19 +1422,6 @@
         mTmpTransaction.apply();
     }
 
-    private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
-            Rect position) {
-        onSetSurfacePositionAndScaleRT(t, surface,
-                position.left /*positionLeft*/,
-                position.top /*positionTop*/,
-                position.width() / (float) mSurfaceWidth /*postScaleX*/,
-                position.height() / (float) mSurfaceHeight /*postScaleY*/);
-
-        if (mViewVisibility) {
-            t.show(surface);
-        }
-    }
-
     /**
      * @return The last render position of the backing surface or an empty rect.
      *
@@ -1421,13 +1431,6 @@
         return mRTLastReportedPosition;
     }
 
-    private void setParentSpaceRectangle(Rect position, long frameNumber, Transaction t) {
-        final ViewRootImpl viewRoot = getViewRootImpl();
-        applySurfaceTransforms(mSurfaceControl, t, position);
-        applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
-        applyOrMergeTransaction(t, frameNumber);
-    }
-
     private void applyOrMergeTransaction(Transaction t, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
         boolean useBLAST = viewRoot != null && useBLASTSync(viewRoot);
@@ -1440,9 +1443,24 @@
     }
 
     private Rect mRTLastReportedPosition = new Rect();
+    private Point mRTLastReportedSurfaceSize = new Point();
 
-    private RenderNode.PositionUpdateListener mPositionListener =
-            new RenderNode.PositionUpdateListener() {
+    private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
+        int mRtSurfaceWidth = -1;
+        int mRtSurfaceHeight = -1;
+        private final SurfaceControl.Transaction mPositionChangedTransaction =
+                new SurfaceControl.Transaction();
+        boolean mPendingTransaction = false;
+
+        SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight,
+                @Nullable Transaction t) {
+            mRtSurfaceWidth = surfaceWidth;
+            mRtSurfaceHeight = surfaceHeight;
+            if (t != null) {
+                mPositionChangedTransaction.merge(t);
+                mPendingTransaction = true;
+            }
+        }
 
         @Override
         public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
@@ -1464,21 +1482,34 @@
             if (mRTLastReportedPosition.left == left
                     && mRTLastReportedPosition.top == top
                     && mRTLastReportedPosition.right == right
-                    && mRTLastReportedPosition.bottom == bottom) {
+                    && mRTLastReportedPosition.bottom == bottom
+                    && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+                    && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
+                    && !mPendingTransaction) {
                 return;
             }
             try {
                 if (DEBUG_POSITION) {
                     Log.d(TAG, String.format(
                             "%d updateSurfacePosition RenderWorker, frameNr = %d, "
-                                    + "position = [%d, %d, %d, %d]",
-                            System.identityHashCode(this), frameNumber,
-                            left, top, right, bottom));
+                                    + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+                            System.identityHashCode(SurfaceView.this), frameNumber,
+                            left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
                 }
                 mRTLastReportedPosition.set(left, top, right, bottom);
-                setParentSpaceRectangle(mRTLastReportedPosition, frameNumber,
-                        mPositionChangedTransaction);
-                // Now overwrite mRTLastReportedPosition with our values
+                mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
+                onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
+                        mRTLastReportedPosition.left /*positionLeft*/,
+                        mRTLastReportedPosition.top /*positionTop*/,
+                        mRTLastReportedPosition.width() / (float) mRtSurfaceWidth /*postScaleX*/,
+                        mRTLastReportedPosition.height() / (float) mRtSurfaceHeight /*postScaleY*/);
+                if (mViewVisibility) {
+                    mPositionChangedTransaction.show(mSurfaceControl);
+                }
+                applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
+                        getViewRootImpl().mSurface, frameNumber);
+                applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+                mPendingTransaction = false;
             } catch (Exception ex) {
                 Log.e(TAG, "Exception from repositionChild", ex);
             }
@@ -1502,7 +1533,13 @@
                         System.identityHashCode(this), frameNumber));
             }
             mRTLastReportedPosition.setEmpty();
-
+            mRTLastReportedSurfaceSize.set(-1, -1);
+            if (mPendingTransaction) {
+                Log.w(TAG, System.identityHashCode(SurfaceView.this)
+                        + "Pending transaction cleared.");
+                mPositionChangedTransaction.clear();
+                mPendingTransaction = false;
+            }
             if (mSurfaceControl == null) {
                 return;
             }
@@ -1521,7 +1558,9 @@
                 mRtHandlingPositionUpdates = false;
             }
         }
-    };
+    }
+
+    private SurfaceViewPositionUpdateListener mPositionListener = null;
 
     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
         SurfaceHolder.Callback[] callbacks;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f3ebe5b..ffc98d2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19816,6 +19816,9 @@
     /**
      * Check if this view can be scrolled horizontally in a certain direction.
      *
+     * <p>This is without regard to whether the view is enabled or not, or if it will scroll
+     * in response to user input or not.
+     *
      * @param direction Negative to check scrolling left, positive to check scrolling right.
      * @return true if this view can be scrolled in the specified direction, false otherwise.
      */
@@ -19833,6 +19836,9 @@
     /**
      * Check if this view can be scrolled vertically in a certain direction.
      *
+     * <p>This is without regard to whether the view is enabled or not, or if it will scroll
+     * in response to user input or not.
+     *
      * @param direction Negative to check scrolling up, positive to check scrolling down.
      * @return true if this view can be scrolled in the specified direction, false otherwise.
      */
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 0a3d0da..495edab 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -600,6 +600,8 @@
     }
 
     /**
+     * Used for both key and motion events.
+     *
      * @return the duration in milliseconds before a press turns into
      * a long press
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 80aa40b..ec21a58 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2519,6 +2519,14 @@
                 || lp.type == TYPE_VOLUME_OVERLAY;
     }
 
+    private Rect getWindowBoundsInsetSystemBars() {
+        final Rect bounds = new Rect(
+                mContext.getResources().getConfiguration().windowConfiguration.getBounds());
+        bounds.inset(mInsetsController.getState().calculateInsets(
+                bounds, Type.systemBars(), false /* ignoreVisibility */));
+        return bounds;
+    }
+
     int dipToPx(int dip) {
         final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
         return (int) (displayMetrics.density * dip + 0.5f);
@@ -2605,8 +2613,9 @@
                     || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                 // For wrap content, we have to remeasure later on anyways. Use size consistent with
                 // below so we get best use of the measure cache.
-                desiredWindowWidth = dipToPx(config.screenWidthDp);
-                desiredWindowHeight = dipToPx(config.screenHeightDp);
+                final Rect bounds = getWindowBoundsInsetSystemBars();
+                desiredWindowWidth = bounds.width();
+                desiredWindowHeight = bounds.height();
             } else {
                 // After addToDisplay, the frame contains the frameHint from window manager, which
                 // for most windows is going to be the same size as the result of relayoutWindow.
@@ -2683,9 +2692,9 @@
                         desiredWindowWidth = size.x;
                         desiredWindowHeight = size.y;
                     } else {
-                        Configuration config = res.getConfiguration();
-                        desiredWindowWidth = dipToPx(config.screenWidthDp);
-                        desiredWindowHeight = dipToPx(config.screenHeightDp);
+                        final Rect bounds = getWindowBoundsInsetSystemBars();
+                        desiredWindowWidth = bounds.width();
+                        desiredWindowHeight = bounds.height();
                     }
                 }
             }
@@ -9927,7 +9936,10 @@
         if (!mUseMTRenderer) {
             return;
         }
-        mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
+        // Only wait if it will report next draw.
+        if (mReportNextDraw) {
+            mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
+        }
         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
             mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index fcfb0ab..eb410ab 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -400,6 +400,11 @@
      */
     int TRANSIT_PIP = 10;
     /**
+     * The screen is turning on.
+     * @hide
+     */
+    int TRANSIT_WAKE = 11;
+    /**
      * The first slot for custom transition types. Callers (like Shell) can make use of custom
      * transition types for dealing with special cases. These types are effectively ignored by
      * Core and will just be passed along as part of TransitionInfo objects. An example is
@@ -408,7 +413,7 @@
      * implementation.
      * @hide
      */
-    int TRANSIT_FIRST_CUSTOM = 11;
+    int TRANSIT_FIRST_CUSTOM = 12;
 
     /**
      * @hide
@@ -425,6 +430,7 @@
             TRANSIT_KEYGUARD_OCCLUDE,
             TRANSIT_KEYGUARD_UNOCCLUDE,
             TRANSIT_PIP,
+            TRANSIT_WAKE,
             TRANSIT_FIRST_CUSTOM
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -937,6 +943,8 @@
             case TRANSIT_KEYGUARD_GOING_AWAY: return "KEYGUARD_GOING_AWAY";
             case TRANSIT_KEYGUARD_OCCLUDE: return "KEYGUARD_OCCLUDE";
             case TRANSIT_KEYGUARD_UNOCCLUDE: return "KEYGUARD_UNOCCLUDE";
+            case TRANSIT_PIP: return "PIP";
+            case TRANSIT_WAKE: return "WAKE";
             case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM";
             default:
                 if (type > TRANSIT_FIRST_CUSTOM) {
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 5f036a3..5185dc2 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -843,9 +843,14 @@
     /**
      * Called back when the connected IME switches between fullscreen and normal modes.
      *
-     * <p>Note: On {@link android.os.Build.VERSION_CODES#O} and later devices, input methods are no
-     * longer allowed to directly call this method at any time. To signal this event in the target
-     * application, input methods should always call
+     * <p><p><strong>Editor authors:</strong> There is a bug on
+     * {@link android.os.Build.VERSION_CODES#O} and later devices that this method is called back
+     * on the main thread even when {@link #getHandler()} is overridden.  This bug is fixed in
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU}.</p>
+     *
+     * <p><p><strong>IME authors:</strong> On {@link android.os.Build.VERSION_CODES#O} and later
+     * devices, input methods are no longer allowed to directly call this method at any time.
+     * To signal this event in the target application, input methods should always call
      * {@link InputMethodService#updateFullscreenMode()} instead. This approach should work on API
      * {@link android.os.Build.VERSION_CODES#N_MR1} and prior devices.</p>
      *
@@ -927,14 +932,20 @@
     boolean requestCursorUpdates(int cursorUpdateMode);
 
     /**
-     * Called by the {@link InputMethodManager} to enable application developers to specify a
-     * dedicated {@link Handler} on which incoming IPC method calls from input methods will be
-     * dispatched.
+     * Called by the system to enable application developers to specify a dedicated thread on which
+     * {@link InputConnection} methods are called back.
      *
-     * <p>Note: This does nothing when called from input methods.</p>
+     * <p><strong>Editor authors</strong>: although you can return your custom subclasses of
+     * {@link Handler}, the system only uses {@link android.os.Looper} returned from
+     * {@link Handler#getLooper()}.  You cannot intercept or cancel {@link InputConnection}
+     * callbacks by implementing this method.</p>
+     *
+     * <p><strong>IME authors</strong>: This method is not intended to be called from the IME.  You
+     * will always receive {@code null}.</p>
      *
      * @return {@code null} to use the default {@link Handler}.
      */
+    @Nullable
     Handler getHandler();
 
     /**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e8e5630..ab7e5a9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -87,18 +87,18 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputBindResult;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.inputmethod.RemoteInputConnectionImpl;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.inputmethod.StartInputFlags;
 import com.android.internal.inputmethod.StartInputReason;
 import com.android.internal.inputmethod.UnbindReason;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.view.IInputConnectionWrapper;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
-import com.android.internal.view.InputBindResult;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -365,7 +365,7 @@
     final H mH;
 
     // Our generic input connection if the current target does not have its own.
-    private final IInputConnectionWrapper mFallbackInputConnection;
+    private final RemoteInputConnectionImpl mFallbackInputConnection;
 
     private final int mDisplayId;
 
@@ -407,7 +407,7 @@
     /**
      * The InputConnection that was last retrieved from the served view.
      */
-    IInputConnectionWrapper mServedInputConnection;
+    RemoteInputConnectionImpl mServedInputConnection;
     /**
      * The completions that were last provided by the served view.
      */
@@ -950,15 +950,15 @@
                 }
                 case MSG_REPORT_FULLSCREEN_MODE: {
                     final boolean fullscreen = msg.arg1 != 0;
-                    InputConnection ic = null;
+                    RemoteInputConnectionImpl ic = null;
                     synchronized (mH) {
                         if (mFullscreenMode != fullscreen && mServedInputConnection != null) {
-                            ic = mServedInputConnection.getInputConnection();
+                            ic = mServedInputConnection;
                             mFullscreenMode = fullscreen;
                         }
                     }
                     if (ic != null) {
-                        ic.reportFullscreenMode(fullscreen);
+                        ic.dispatchReportFullscreenMode(fullscreen);
                     }
                     return;
                 }
@@ -1120,7 +1120,7 @@
         mMainLooper = looper;
         mH = new H(looper);
         mDisplayId = displayId;
-        mFallbackInputConnection = new IInputConnectionWrapper(looper,
+        mFallbackInputConnection = new RemoteInputConnectionImpl(looper,
                 new BaseInputConnection(this, false), this, null);
     }
 
@@ -1199,18 +1199,6 @@
     }
 
     /**
-     * No longer used.  Do not use.
-     *
-     * TODO(b/192412909) Remove this method.
-     *
-     * @deprecated Was kept due to {@link UnsupportedAppUsage}.  Will be removed soon.
-     * @hide
-     */
-    public IInputMethodClient getClient() {
-        return mClient;
-    }
-
-    /**
      * Returns the list of installed input methods.
      *
      * <p>On multi user environment, this API returns a result for the calling process user.</p>
@@ -1393,8 +1381,7 @@
     public boolean isAcceptingText() {
         checkFocus();
         synchronized (mH) {
-            return mServedInputConnection != null
-                    && mServedInputConnection.getInputConnection() != null;
+            return mServedInputConnection != null && !mServedInputConnection.isFinished();
         }
     }
 
@@ -1950,7 +1937,7 @@
                 mServedInputConnection.deactivate();
                 mServedInputConnection = null;
             }
-            IInputConnectionWrapper servedInputConnection;
+            RemoteInputConnectionImpl servedInputConnection;
             final int missingMethodFlags;
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
@@ -1967,7 +1954,7 @@
                 } else {
                     icHandler = ic.getHandler();
                 }
-                servedInputConnection = new IInputConnectionWrapper(
+                servedInputConnection = new RemoteInputConnectionImpl(
                         icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
             } else {
                 servedInputConnection = null;
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index ae927cf..e31eabb 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
 import android.annotation.UserIdInt;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -114,6 +115,7 @@
      * @throws ServiceNotFoundException When {@link TextServicesManager} is not available.
      * @hide
      */
+    @UserHandleAware
     @NonNull
     public static TextServicesManager createInstance(@NonNull Context context)
             throws ServiceNotFoundException {
@@ -178,6 +180,7 @@
      * languages in settings will be returned.
      * @return a spell checker session of the spell checker
      */
+    @UserHandleAware
     @Nullable
     public SpellCheckerSession newSpellCheckerSession(@Nullable Bundle bundle,
             @Nullable Locale locale,
@@ -208,6 +211,7 @@
      * @param listener a spell checker session lister for getting results from the spell checker.
      * @return The spell checker session of the spell checker.
      */
+    @UserHandleAware
     @Nullable
     public SpellCheckerSession newSpellCheckerSession(
             @NonNull SpellCheckerSessionParams params,
@@ -283,6 +287,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
             publicAlternatives = "Use {@link #getEnabledSpellCheckerInfos()} instead.")
+    @UserHandleAware
     public SpellCheckerInfo[] getEnabledSpellCheckers() {
         try {
             final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId);
@@ -300,6 +305,7 @@
      *
      * @return The list of currently enabled spell checkers.
      */
+    @UserHandleAware
     @NonNull
     public List<SpellCheckerInfo> getEnabledSpellCheckerInfos() {
         final SpellCheckerInfo[] enabledSpellCheckers = getEnabledSpellCheckers();
@@ -312,6 +318,7 @@
      *
      * @return The current active spell checker info.
      */
+    @UserHandleAware
     @Nullable
     public SpellCheckerInfo getCurrentSpellCheckerInfo() {
         try {
@@ -328,6 +335,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
             publicAlternatives = "Use {@link #getCurrentSpellCheckerInfo()} instead.")
+    @UserHandleAware
     @Nullable
     public SpellCheckerInfo getCurrentSpellChecker() {
         return getCurrentSpellCheckerInfo();
@@ -343,6 +351,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @UserHandleAware
     @Nullable
     public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
             boolean allowImplicitlySelectedSubtype) {
@@ -358,6 +367,7 @@
      *
      * @return {@code true} if spell checker is enabled, {@code false} otherwise.
      */
+    @UserHandleAware
     public boolean isSpellCheckerEnabled() {
         try {
             return mService.isSpellCheckerEnabled(mUserId);
@@ -366,6 +376,7 @@
         }
     }
 
+    @UserHandleAware
     void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
         try {
             mService.finishSpellCheckerService(mUserId, listener);
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index edd0d16..606f39d 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -18,6 +18,7 @@
 
 import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
 import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS;
+import static android.view.translation.UiTranslationController.DEBUG;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -38,7 +39,6 @@
 import com.android.internal.os.IResultReceiver;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -395,27 +395,26 @@
 
     private static class TranslationResponseCallbackImpl extends ITranslationCallback.Stub {
 
-        private final WeakReference<Consumer<TranslationResponse>> mCallback;
-        private final WeakReference<Executor> mExecutor;
+        private final Consumer<TranslationResponse> mCallback;
+        private final Executor mExecutor;
 
         TranslationResponseCallbackImpl(Consumer<TranslationResponse> callback, Executor executor) {
-            mCallback = new WeakReference<>(callback);
-            mExecutor = new WeakReference<>(executor);
+            mCallback = callback;
+            mExecutor = executor;
         }
 
         @Override
         public void onTranslationResponse(TranslationResponse response) throws RemoteException {
-            final Consumer<TranslationResponse> callback = mCallback.get();
+            if (DEBUG) {
+                Log.i(TAG, "onTranslationResponse called.");
+            }
             final Runnable runnable =
-                    () -> callback.accept(response);
-            if (callback != null) {
-                final Executor executor = mExecutor.get();
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(runnable);
-                } finally {
-                    restoreCallingIdentity(token);
-                }
+                    () -> mCallback.accept(response);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(runnable);
+            } finally {
+                restoreCallingIdentity(token);
             }
         }
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 87f4a15..a45a91e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2543,33 +2543,32 @@
             return;
         }
 
-        boolean isItemEnabled = view.isEnabled() && isEnabled();
+        boolean isItemActionable = isEnabled();
         final ViewGroup.LayoutParams lp = view.getLayoutParams();
         if (lp instanceof AbsListView.LayoutParams) {
-            isItemEnabled &= ((AbsListView.LayoutParams) lp).isEnabled;
+            isItemActionable &= ((AbsListView.LayoutParams) lp).isEnabled;
         }
 
-        info.setEnabled(isItemEnabled);
-
         if (position == getSelectedItemPosition()) {
             info.setSelected(true);
-            addAccessibilityActionIfEnabled(info, isItemEnabled,
+            addAccessibilityActionIfEnabled(info, isItemActionable,
                     AccessibilityAction.ACTION_CLEAR_SELECTION);
         } else  {
-            addAccessibilityActionIfEnabled(info, isItemEnabled,
+            addAccessibilityActionIfEnabled(info, isItemActionable,
                     AccessibilityAction.ACTION_SELECT);
         }
 
         if (isItemClickable(view)) {
-            addAccessibilityActionIfEnabled(info, isItemEnabled, AccessibilityAction.ACTION_CLICK);
+            addAccessibilityActionIfEnabled(info, isItemActionable,
+                    AccessibilityAction.ACTION_CLICK);
             // A disabled item is a separator which should not be clickable.
-            info.setClickable(isItemEnabled);
+            info.setClickable(isItemActionable);
         }
 
         if (isLongClickable()) {
-            addAccessibilityActionIfEnabled(info, isItemEnabled,
+            addAccessibilityActionIfEnabled(info, isItemActionable,
                     AccessibilityAction.ACTION_LONG_CLICK);
-            info.setLongClickable(true);
+            info.setLongClickable(isItemActionable);
         }
     }
 
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 607e316..34facc4 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.WindowManager.TransitionType;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -26,6 +27,7 @@
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.WindowManager;
 
 /**
  * A parcelable filter that can be used for rerouting transitions to a remote. This is a local
@@ -52,7 +54,10 @@
      * When non-null: this is a list of transition types that this filter applies to. This filter
      * will fail for transitions that aren't one of these types.
      */
-    @Nullable public int[] mTypeSet = null;
+    @Nullable public @TransitionType int[] mTypeSet = null;
+
+    /** All flags must be set on a transition. */
+    public @WindowManager.TransitionFlags int mFlags = 0;
 
     /**
      * A list of required changes. To pass, a transition must meet all requirements.
@@ -64,6 +69,7 @@
 
     private TransitionFilter(Parcel in) {
         mTypeSet = in.createIntArray();
+        mFlags = in.readInt();
         mRequirements = in.createTypedArray(Requirement.CREATOR);
     }
 
@@ -80,10 +86,16 @@
             }
             if (!typePass) return false;
         }
+        if ((info.getFlags() & mFlags) != mFlags) {
+            return false;
+        }
         // Make sure info meets all of the requirements.
         if (mRequirements != null) {
             for (int i = 0; i < mRequirements.length; ++i) {
-                if (!mRequirements[i].matches(info)) return false;
+                final boolean matches = mRequirements[i].matches(info);
+                if (matches == mRequirements[i].mNot) {
+                    return false;
+                }
             }
         }
         return true;
@@ -93,6 +105,7 @@
     /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeIntArray(mTypeSet);
+        dest.writeInt(mFlags);
         dest.writeTypedArray(mRequirements, flags);
     }
 
@@ -122,10 +135,11 @@
         sb.append("{types=[");
         if (mTypeSet != null) {
             for (int i = 0; i < mTypeSet.length; ++i) {
-                sb.append((i == 0 ? "" : ",") + mTypeSet[i]);
+                sb.append((i == 0 ? "" : ",") + WindowManager.transitTypeToString(mTypeSet[i]));
             }
         }
-        sb.append("] checks=[");
+        sb.append("] flags=0x" + Integer.toHexString(mFlags));
+        sb.append(" checks=[");
         if (mRequirements != null) {
             for (int i = 0; i < mRequirements.length; ++i) {
                 sb.append((i == 0 ? "" : ",") + mRequirements[i]);
@@ -140,7 +154,21 @@
      */
     public static final class Requirement implements Parcelable {
         public int mActivityType = ACTIVITY_TYPE_UNDEFINED;
+
+        /** This only matches if the change is independent of its parents. */
+        public boolean mMustBeIndependent = true;
+
+        /** If this matches, the parent filter will fail */
+        public boolean mNot = false;
+
         public int[] mModes = null;
+
+        /** Matches only if all the flags here are set on the change. */
+        public @TransitionInfo.ChangeFlags int mFlags = 0;
+
+        /** If this needs to be a task. */
+        public boolean mMustBeTask = false;
+
         public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY;
         public ComponentName mTopActivity;
 
@@ -149,7 +177,11 @@
 
         private Requirement(Parcel in) {
             mActivityType = in.readInt();
+            mMustBeIndependent = in.readBoolean();
+            mNot = in.readBoolean();
             mModes = in.createIntArray();
+            mFlags = in.readInt();
+            mMustBeTask = in.readBoolean();
             mOrder = in.readInt();
             mTopActivity = in.readTypedObject(ComponentName.CREATOR);
         }
@@ -158,7 +190,7 @@
         boolean matches(@NonNull TransitionInfo info) {
             for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                 final TransitionInfo.Change change = info.getChanges().get(i);
-                if (!TransitionInfo.isIndependent(change, info)) {
+                if (mMustBeIndependent && !TransitionInfo.isIndependent(change, info)) {
                     // Only look at independent animating windows.
                     continue;
                 }
@@ -182,6 +214,12 @@
                     }
                     if (!pass) continue;
                 }
+                if ((change.getFlags() & mFlags) != mFlags) {
+                    continue;
+                }
+                if (mMustBeTask && change.getTaskInfo() == null) {
+                    continue;
+                }
                 return true;
             }
             return false;
@@ -207,7 +245,11 @@
         /** @hide */
         public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeInt(mActivityType);
+            dest.writeBoolean(mMustBeIndependent);
+            dest.writeBoolean(mNot);
             dest.writeIntArray(mModes);
+            dest.writeInt(mFlags);
+            dest.writeBoolean(mMustBeTask);
             dest.writeInt(mOrder);
             dest.writeTypedObject(mTopActivity, flags);
         }
@@ -235,7 +277,10 @@
         @Override
         public String toString() {
             StringBuilder out = new StringBuilder();
-            out.append("{atype=" + WindowConfiguration.activityTypeToString(mActivityType));
+            out.append('{');
+            if (mNot) out.append("NOT ");
+            out.append("atype=" + WindowConfiguration.activityTypeToString(mActivityType));
+            out.append(" independent=" + mMustBeIndependent);
             out.append(" modes=[");
             if (mModes != null) {
                 for (int i = 0; i < mModes.length; ++i) {
@@ -243,8 +288,11 @@
                 }
             }
             out.append("]").toString();
+            out.append(" flags=" + TransitionInfo.flagsToString(mFlags));
+            out.append(" mustBeTask=" + mMustBeTask);
             out.append(" order=" + containerOrderToString(mOrder));
             out.append(" topActivity=").append(mTopActivity);
+            out.append("}");
             return out.toString();
         }
     }
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index ebc66ef..702a8ba 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -23,12 +23,15 @@
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
 import static android.view.WindowManager.transitTypeToString;
 
 import android.annotation.IntDef;
@@ -42,7 +45,6 @@
 import android.os.Parcelable;
 import android.view.Surface;
 import android.view.SurfaceControl;
-import android.view.WindowManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -90,8 +92,19 @@
     /** The container is the display. */
     public static final int FLAG_IS_DISPLAY = 1 << 5;
 
+    /** The container can show on top of lock screen. */
+    public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6;
+
+    /**
+     * Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
+     * used to prevent seamless rotation.
+     * TODO(b/194540864): Once we can include all windows in transition, then replace this with
+     *         something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
+     */
+    public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
+
     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
-    public static final int FLAG_FIRST_CUSTOM = 1 << 6;
+    public static final int FLAG_FIRST_CUSTOM = 1 << 8;
 
     /** @hide */
     @IntDef(prefix = { "FLAG_" }, value = {
@@ -102,12 +115,14 @@
             FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
             FLAG_IS_VOICE_INTERACTION,
             FLAG_IS_DISPLAY,
+            FLAG_OCCLUDES_KEYGUARD,
+            FLAG_DISPLAY_HAS_ALERT_WINDOWS,
             FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
 
-    private final @WindowManager.TransitionOldType int mType;
-    private final @WindowManager.TransitionFlags int mFlags;
+    private final @TransitionType int mType;
+    private final @TransitionFlags int mFlags;
     private final ArrayList<Change> mChanges = new ArrayList<>();
 
     private SurfaceControl mRootLeash;
@@ -116,8 +131,7 @@
     private AnimationOptions mOptions;
 
     /** @hide */
-    public TransitionInfo(@WindowManager.TransitionOldType int type,
-            @WindowManager.TransitionFlags int flags) {
+    public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
         mType = type;
         mFlags = flags;
     }
@@ -173,7 +187,7 @@
         mOptions = options;
     }
 
-    public int getType() {
+    public @TransitionType int getType() {
         return mType;
     }
 
@@ -205,6 +219,10 @@
         return mOptions;
     }
 
+    /**
+     * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom
+     *         in Z (meaning index 0 is the top-most container).
+     */
     @NonNull
     public List<Change> getChanges() {
         return mChanges;
@@ -234,7 +252,7 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags)
+        sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags)
                 + " ro=" + mRootOffset + " c=[");
         for (int i = 0; i < mChanges.size(); ++i) {
             if (i > 0) {
@@ -283,6 +301,12 @@
         if ((flags & FLAG_IS_DISPLAY) != 0) {
             sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY");
         }
+        if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) {
+            sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD");
+        }
+        if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
+            sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS");
+        }
         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
             sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
         }
@@ -328,8 +352,10 @@
         private final Rect mEndAbsBounds = new Rect();
         private final Point mEndRelOffset = new Point();
         private ActivityManager.RunningTaskInfo mTaskInfo = null;
+        private boolean mAllowEnterPip;
         private int mStartRotation = ROTATION_UNDEFINED;
         private int mEndRotation = ROTATION_UNDEFINED;
+        private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
 
         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
             mContainer = container;
@@ -347,8 +373,10 @@
             mEndAbsBounds.readFromParcel(in);
             mEndRelOffset.readFromParcel(in);
             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+            mAllowEnterPip = in.readBoolean();
             mStartRotation = in.readInt();
             mEndRotation = in.readInt();
+            mRotationAnimation = in.readInt();
         }
 
         /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -389,12 +417,25 @@
             mTaskInfo = taskInfo;
         }
 
+        /** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */
+        public void setAllowEnterPip(boolean allowEnterPip) {
+            mAllowEnterPip = allowEnterPip;
+        }
+
         /** Sets the start and end rotation of this container. */
         public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
             mStartRotation = start;
             mEndRotation = end;
         }
 
+        /**
+         * Sets the app-requested animation type for rotation. Will be one of the
+         * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
+         */
+        public void setRotationAnimation(int anim) {
+            mRotationAnimation = anim;
+        }
+
         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
         @Nullable
         public WindowContainerToken getContainer() {
@@ -458,6 +499,10 @@
             return mTaskInfo;
         }
 
+        public boolean getAllowEnterPip() {
+            return mAllowEnterPip;
+        }
+
         public int getStartRotation() {
             return mStartRotation;
         }
@@ -466,6 +511,11 @@
             return mEndRotation;
         }
 
+        /** @return the rotation animation. */
+        public int getRotationAnimation() {
+            return mRotationAnimation;
+        }
+
         /** @hide */
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -478,8 +528,10 @@
             mEndAbsBounds.writeToParcel(dest, flags);
             mEndRelOffset.writeToParcel(dest, flags);
             dest.writeTypedObject(mTaskInfo, flags);
+            dest.writeBoolean(mAllowEnterPip);
             dest.writeInt(mStartRotation);
             dest.writeInt(mEndRotation);
+            dest.writeInt(mRotationAnimation);
         }
 
         @NonNull
@@ -507,7 +559,7 @@
             return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
                     + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
-                    + mStartRotation + "->" + mEndRotation + "}";
+                    + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}";
         }
     }
 
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index a735bbc..342df4f 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -506,15 +506,17 @@
      * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
      * fragmentTokens when that TaskFragments haven't been created (but will be created in the same
      * {@link WindowContainerTransaction}).
+     * To reset it, pass {@code null} for {@code fragmentToken2}.
      * @param fragmentToken1    client assigned unique token to create TaskFragment with specified
      *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
      * @param fragmentToken2    client assigned unique token to create TaskFragment with specified
-     *                          in {@link TaskFragmentCreationParams#getFragmentToken()}.
+     *                          in {@link TaskFragmentCreationParams#getFragmentToken()}. If it is
+     *                          {@code null}, the transaction will reset the adjacent TaskFragment.
      * @hide
      */
     @NonNull
     public WindowContainerTransaction setAdjacentTaskFragments(
-            @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2) {
+            @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) {
         final HierarchyOp hierarchyOp =
                 new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
                         .setContainer(fragmentToken1)
diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
index 3a108e7..06640cb 100644
--- a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
@@ -18,5 +18,6 @@
 
 // Iterface to observe op starts
 oneway interface IAppOpsStartedCallback {
-    void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode);
+    void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode,
+    int startedType, int attributionFlags, int attributionChainId);
 }
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index 55a2052..c9a9e51 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -16,11 +16,9 @@
 
 package com.android.internal.display;
 
-import android.annotation.NonNull;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
-import android.hardware.display.BrightnessInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.net.Uri;
@@ -63,10 +61,10 @@
                     updateBrightnessFloatFromInt(msg.arg1);
                     break;
                 case MSG_UPDATE_INT:
-                    updateBrightnessIntFromFloat((BrightnessInfo) msg.obj);
+                    updateBrightnessIntFromFloat(Float.intBitsToFloat(msg.arg1));
                     break;
                 case MSG_UPDATE_BOTH:
-                    updateBoth((BrightnessInfo) msg.obj, Float.intBitsToFloat(msg.arg1));
+                    updateBoth(Float.intBitsToFloat(msg.arg1));
                     break;
                 default:
                     super.handleMessage(msg);
@@ -97,11 +95,11 @@
         brightnessSyncObserver = new BrightnessSyncObserver();
         brightnessSyncObserver.startObserving();
 
-        final BrightnessInfo brightnessInfo = getBrightnessInfo();
+        final float currentFloatBrightness = getScreenBrightnessFloat();
         final int currentIntBrightness = getScreenBrightnessInt(mContext);
 
-        if (brightnessInfo != null && !Float.isNaN(brightnessInfo.brightness)) {
-            updateBrightnessIntFromFloat(brightnessInfo);
+        if (!Float.isNaN(currentFloatBrightness)) {
+            updateBrightnessIntFromFloat(currentFloatBrightness);
         } else if (currentIntBrightness != -1) {
             updateBrightnessFloatFromInt(currentIntBrightness);
         } else {
@@ -114,23 +112,15 @@
 
     /**
      * Converts between the int brightness system and the float brightness system.
-     *
-     * @param brightnessInt The int brightness value to convert.
      */
     public static float brightnessIntToFloat(int brightnessInt) {
-        return brightnessIntToFloat(brightnessInt, null);
-    }
-
-    private static float brightnessIntToFloat(int brightnessInt, BrightnessInfo info) {
         if (brightnessInt == PowerManager.BRIGHTNESS_OFF) {
             return PowerManager.BRIGHTNESS_OFF_FLOAT;
         } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) {
             return PowerManager.BRIGHTNESS_INVALID_FLOAT;
         } else {
-            final float minFloat = info != null
-                    ? info.brightnessMinimum : PowerManager.BRIGHTNESS_MIN;
-            final float maxFloat = info != null
-                    ? info.brightnessMaximum : PowerManager.BRIGHTNESS_MAX;
+            final float minFloat = PowerManager.BRIGHTNESS_MIN;
+            final float maxFloat = PowerManager.BRIGHTNESS_MAX;
             final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
             final float maxInt = PowerManager.BRIGHTNESS_ON;
             return MathUtils.constrainedMap(minFloat, maxFloat, minInt, maxInt, brightnessInt);
@@ -138,28 +128,29 @@
     }
 
     /**
+     * Converts between the float brightness system and the int brightness system.
+     */
+    public static int brightnessFloatToInt(float brightnessFloat) {
+        return Math.round(brightnessFloatToIntRange(brightnessFloat));
+    }
+
+    /**
      * Translates specified value from the float brightness system to the int brightness system,
      * given the min/max of each range. Accounts for special values such as OFF and invalid values.
      * Value returned as a float primitive (to preserve precision), but is a value within the
      * int-system range.
-     *
-     * @param brightnessFloat The float brightness value to convert.
-     * @param info Brightness information to use in the conversion.
      */
-    public static int brightnessFloatToInt(float brightnessFloat, BrightnessInfo info) {
+    public static float brightnessFloatToIntRange(float brightnessFloat) {
         if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {
             return PowerManager.BRIGHTNESS_OFF;
         } else if (Float.isNaN(brightnessFloat)) {
             return PowerManager.BRIGHTNESS_INVALID;
         } else {
-            final float minFloat = info != null
-                    ? info.brightnessMinimum : PowerManager.BRIGHTNESS_MIN;
-            final float maxFloat = info != null
-                    ? info.brightnessMaximum : PowerManager.BRIGHTNESS_MAX;
+            final float minFloat = PowerManager.BRIGHTNESS_MIN;
+            final float maxFloat = PowerManager.BRIGHTNESS_MAX;
             final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
             final float maxInt = PowerManager.BRIGHTNESS_ON;
-            return Math.round(MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat,
-                    brightnessFloat));
+            return MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat, brightnessFloat);
         }
     }
 
@@ -194,37 +185,35 @@
      * @param value Brightness value as int to store in the float setting.
      */
     private void updateBrightnessFloatFromInt(int value) {
-        final BrightnessInfo info = getBrightnessInfo();
-        if (brightnessFloatToInt(mPreferredSettingValue, info) == value) {
+        if (brightnessFloatToInt(mPreferredSettingValue) == value) {
             return;
         }
 
-        mPreferredSettingValue = brightnessIntToFloat(value, info);
+        mPreferredSettingValue = brightnessIntToFloat(value);
         final int newBrightnessAsIntBits = Float.floatToIntBits(mPreferredSettingValue);
         mHandler.removeMessages(MSG_UPDATE_BOTH);
         mHandler.obtainMessage(MSG_UPDATE_BOTH, newBrightnessAsIntBits, 0).sendToTarget();
     }
 
     /**
-     * Updates the settings from the specified {@link BrightnessInfo}. This is called whenever the
-     * float brightness changed from DisplayManager. mPreferredSettingValue holds the most recently
-     * updated brightness value as a float that we would like the display to be set to.
+     * Updates the settings based on a passed in float value. This is called whenever the float
+     * setting changes. mPreferredSettingValue holds the most recently updated brightness value
+     * as a float that we would like the display to be set to.
      *
      * We then schedule an update to both the int and float settings, but, remove all the other
      * messages to update all, to prevent us getting stuck in a loop.
      *
-     * @param brightnessInfo Current brightness information
+     * @param value Brightness setting as float to store in int setting.
      */
-    private void updateBrightnessIntFromFloat(@NonNull BrightnessInfo brightnessInfo) {
-        final float value = brightnessInfo.brightness;
+    private void updateBrightnessIntFromFloat(float value) {
         if (floatEquals(mPreferredSettingValue, value)) {
             return;
         }
 
         mPreferredSettingValue = value;
+        final int newBrightnessAsIntBits = Float.floatToIntBits(mPreferredSettingValue);
         mHandler.removeMessages(MSG_UPDATE_BOTH);
-        mHandler.obtainMessage(MSG_UPDATE_BOTH, Float.floatToIntBits(value), 0, brightnessInfo)
-                .sendToTarget();
+        mHandler.obtainMessage(MSG_UPDATE_BOTH, newBrightnessAsIntBits, 0).sendToTarget();
     }
 
 
@@ -233,24 +222,16 @@
      * mDisplayManager.setBrightness automatically checks for changes
      * Settings.System.putIntForUser needs to be checked, to prevent an extra callback to this class
      *
-     * @param brightnessInfo Brightness information, takes precedent over newBrightnessFloat
      * @param newBrightnessFloat Brightness setting as float to store in both settings
      */
-    private void updateBoth(BrightnessInfo brightnessInfo, float newBrightnessFloat) {
-        int newBrightnessInt = brightnessFloatToInt(newBrightnessFloat, brightnessInfo);
+    private void updateBoth(float newBrightnessFloat) {
+        int newBrightnessInt = brightnessFloatToInt(newBrightnessFloat);
         mDisplayManager.setBrightness(Display.DEFAULT_DISPLAY, newBrightnessFloat);
         if (getScreenBrightnessInt(mContext) != newBrightnessInt) {
             Settings.System.putIntForUser(mContext.getContentResolver(),
                     Settings.System.SCREEN_BRIGHTNESS, newBrightnessInt, UserHandle.USER_CURRENT);
         }
-    }
 
-    private BrightnessInfo getBrightnessInfo() {
-        final Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
-        if (display != null) {
-            return display.getBrightnessInfo();
-        }
-        return null;
     }
 
     /**
@@ -282,15 +263,10 @@
 
             @Override
             public void onDisplayChanged(int displayId) {
-                if (displayId != Display.DEFAULT_DISPLAY) {
-                    return;
-                }
-
-                final BrightnessInfo info = getBrightnessInfo();
-                if (info != null) {
-                    mHandler.removeMessages(MSG_UPDATE_INT);
-                    mHandler.obtainMessage(MSG_UPDATE_INT, info).sendToTarget();
-                }
+                float currentFloat = getScreenBrightnessFloat();
+                int toSend = Float.floatToIntBits(currentFloat);
+                mHandler.removeMessages(MSG_UPDATE_INT);
+                mHandler.obtainMessage(MSG_UPDATE_INT, toSend, 0).sendToTarget();
             }
         };
 
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index db5d066..84391c1 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.util.EventLog;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -601,9 +602,14 @@
         String messageWithStackTrace = message + '\n' + stackTrace;
         Throwable throwable;
         try {
-            Class<?> clazz = Class.forName(className);
-            Constructor<?> constructor = clazz.getConstructor(String.class);
-            throwable = (Throwable) constructor.newInstance(messageWithStackTrace);
+            Class<?> clazz = Class.forName(className, true, Parcelable.class.getClassLoader());
+            if (Throwable.class.isAssignableFrom(clazz)) {
+                Constructor<?> constructor = clazz.getConstructor(String.class);
+                throwable = (Throwable) constructor.newInstance(messageWithStackTrace);
+            } else {
+                android.util.EventLog.writeEvent(0x534e4554, "186530450", -1, "");
+                throwable = new RuntimeException(className + ": " + messageWithStackTrace);
+            }
         } catch (Throwable t) {
             throwable = new RuntimeException(className + ": " + messageWithStackTrace);
             throwable.addSuppressed(t);
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 2b9556d..aca761d 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -17,11 +17,7 @@
 package com.android.internal.inputmethod;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.RemoteException;
-import android.util.Log;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.SurroundingText;
 
 import java.util.function.BooleanSupplier;
 import java.util.function.IntSupplier;
@@ -141,143 +137,4 @@
             callback.onResult(result);
         } catch (RemoteException ignored) { }
     }
-
-    /**
-     * A utility method to reply associated with {@link InputConnectionCommand}.
-     *
-     * @param command {@link InputConnectionCommand} to be replied.
-     * @param result a {@link String} value to be replied.
-     * @param tag tag name to be used for debug output when the invocation fails.
-     */
-    public static void onResult(@NonNull InputConnectionCommand command, boolean result,
-            @Nullable String tag) {
-        if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.BOOLEAN) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result + " due to callback type mismatch."
-                        + " expected=String actual=" + command.mResultCallbackType);
-            }
-            return;
-        }
-        try {
-            IBooleanResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
-        } catch (Throwable e) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result, e);
-            }
-        }
-    }
-
-    /**
-     * A utility method to reply associated with {@link InputConnectionCommand}.
-     *
-     * @param command {@link InputConnectionCommand} to be replied.
-     * @param result an int result value to be replied.
-     * @param tag tag name to be used for debug output when the invocation fails.
-     */
-    public static void onResult(@NonNull InputConnectionCommand command, int result,
-            @Nullable String tag) {
-        if (command.mResultCallbackType != InputConnectionCommand.ResultCallbackType.INT) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result + " due to callback type mismatch."
-                        + " expected=int actual=" + command.mResultCallbackType);
-            }
-            return;
-        }
-        try {
-            IIntResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
-        } catch (Throwable e) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result, e);
-            }
-        }
-    }
-
-    /**
-     * A utility method to reply associated with {@link InputConnectionCommand}.
-     *
-     * @param command {@link InputConnectionCommand} to be replied.
-     * @param result a {@link CharSequence} result value to be replied.
-     * @param tag tag name to be used for debug output when the invocation fails.
-     */
-    public static void onResult(@NonNull InputConnectionCommand command,
-            @Nullable CharSequence result, @Nullable String tag) {
-        if (command.mResultCallbackType
-                != InputConnectionCommand.ResultCallbackType.CHAR_SEQUENCE) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result + " due to callback type mismatch."
-                        + " expected=CharSequence actual=" + command.mResultCallbackType);
-            }
-            return;
-        }
-        try {
-            ICharSequenceResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
-        } catch (Throwable e) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result, e);
-            }
-        }
-    }
-
-    /**
-     * A utility method to reply associated with {@link InputConnectionCommand}.
-     *
-     * @param command {@link InputConnectionCommand} to be replied.
-     * @param result a {@link ExtractedText} result value to be replied.
-     * @param tag tag name to be used for debug output when the invocation fails.
-     */
-    public static void onResult(@NonNull InputConnectionCommand command,
-            @Nullable ExtractedText result, @Nullable String tag) {
-        if (command.mResultCallbackType
-                != InputConnectionCommand.ResultCallbackType.EXTRACTED_TEXT) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result + " due to callback type mismatch."
-                        + " expected=ExtractedText actual=" + command.mResultCallbackType);
-            }
-            return;
-        }
-        try {
-            IExtractedTextResultCallback.Stub.asInterface(command.mResultCallback).onResult(result);
-        } catch (Throwable e) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result, e);
-            }
-        }
-    }
-
-    /**
-     * A utility method to reply associated with {@link InputConnectionCommand}.
-     *
-     * @param command {@link InputConnectionCommand} to be replied.
-     * @param result a {@link SurroundingText} result value to be replied.
-     * @param tag tag name to be used for debug output when the invocation fails.
-     */
-    public static void onResult(@NonNull InputConnectionCommand command,
-            @Nullable SurroundingText result, @Nullable String tag) {
-        if (command.mResultCallbackType
-                != InputConnectionCommand.ResultCallbackType.SURROUNDING_TEXT) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result + " due to callback type mismatch."
-                        + " expected=SurroundingText actual=" + command.mResultCallbackType);
-            }
-            return;
-        }
-        try {
-            ISurroundingTextResultCallback.Stub.asInterface(command.mResultCallback)
-                    .onResult(result);
-        } catch (Throwable e) {
-            if (tag != null) {
-                Log.e(tag, InputMethodDebug.inputConnectionCommandTypeToString(command.mCommandType)
-                        + ": Failed to return result=" + result, e);
-            }
-        }
-    }
 }
diff --git a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
index 7a43a55..977f9a5 100644
--- a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
+++ b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
@@ -18,7 +18,6 @@
 
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.view.KeyEvent;
@@ -33,7 +32,7 @@
 
 /**
  * A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
- * code around {@link InputConnectionCommand}, {@link Completable} and {@link RemoteException}.
+ * code around {@link Completable} and {@link RemoteException}.
  */
 public final class IInputContextInvoker {
 
@@ -56,7 +55,8 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)}.
+     * Invokes {@link IInputContext#getTextAfterCursor(int, int,
+     * com.android.internal.inputmethod.ICharSequenceResultCallback)}.
      *
      * @param length {@code length} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
@@ -67,9 +67,8 @@
     @NonNull
     public Completable.CharSequence getTextAfterCursor(int length, int flags) {
         final Completable.CharSequence value = Completable.createCharSequence();
-        final InputConnectionCommand command = Commands.getTextAfterCursor(length, flags, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -77,7 +76,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)}.
+     * Invokes {@link IInputContext#getTextBeforeCursor(int, int, ICharSequenceResultCallback)}.
      *
      * @param length {@code length} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
@@ -88,9 +87,8 @@
     @NonNull
     public Completable.CharSequence getTextBeforeCursor(int length, int flags) {
         final Completable.CharSequence value = Completable.createCharSequence();
-        final InputConnectionCommand command = Commands.getTextBeforeCursor(length, flags, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -98,7 +96,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#getSelectedText(int)}.
+     * Invokes {@link IInputContext#getSelectedText(int, ICharSequenceResultCallback)}.
      *
      * @param flags {@code flags} parameter to be passed.
      * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
@@ -108,9 +106,8 @@
     @NonNull
     public Completable.CharSequence getSelectedText(int flags) {
         final Completable.CharSequence value = Completable.createCharSequence();
-        final InputConnectionCommand command = Commands.getSelectedText(flags, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -118,8 +115,8 @@
     }
 
     /**
-     * Implements
-     * {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)}.
+     * Invokes
+     * {@link IInputContext#getSurroundingText(int, int, int, ISurroundingTextResultCallback)}.
      *
      * @param beforeLength {@code beforeLength} parameter to be passed.
      * @param afterLength {@code afterLength} parameter to be passed.
@@ -132,10 +129,9 @@
     public Completable.SurroundingText getSurroundingText(int beforeLength, int afterLength,
             int flags) {
         final Completable.SurroundingText value = Completable.createSurroundingText();
-        final InputConnectionCommand command =
-                Commands.getSurroundingText(beforeLength, afterLength, flags, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
+                    ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -143,7 +139,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)}.
+     * Invokes {@link IInputContext#getCursorCapsMode(int, IIntResultCallback)}.
      *
      * @param reqModes {@code reqModes} parameter to be passed.
      * @return {@link Completable.Int} that can be used to retrieve the invocation result.
@@ -153,9 +149,8 @@
     @NonNull
     public Completable.Int getCursorCapsMode(int reqModes) {
         final Completable.Int value = Completable.createInt();
-        final InputConnectionCommand command = Commands.getCursorCapsMode(reqModes, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -163,8 +158,8 @@
     }
 
     /**
-     * Implements
-     * {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}.
+     * Invokes {@link IInputContext#getExtractedText(ExtractedTextRequest, int,
+     * IExtractedTextResultCallback)}.
      *
      * @param request {@code request} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
@@ -175,9 +170,8 @@
     @NonNull
     public Completable.ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         final Completable.ExtractedText value = Completable.createExtractedText();
-        final InputConnectionCommand command = Commands.getExtractedText(request, flags, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -185,7 +179,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#commitText(CharSequence, int)}.
+     * Invokes {@link IInputContext#commitText(CharSequence, int)}.
      *
      * @param text {@code text} parameter to be passed.
      * @param newCursorPosition {@code newCursorPosition} parameter to be passed.
@@ -194,9 +188,8 @@
      */
     @AnyThread
     public boolean commitText(CharSequence text, int newCursorPosition) {
-        final InputConnectionCommand command = Commands.commitText(text, newCursorPosition);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.commitText(text, newCursorPosition);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -204,7 +197,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#commitCompletion(CompletionInfo)}.
+     * Invokes {@link IInputContext#commitCompletion(CompletionInfo)}.
      *
      * @param text {@code text} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -212,9 +205,8 @@
      */
     @AnyThread
     public boolean commitCompletion(CompletionInfo text) {
-        final InputConnectionCommand command = Commands.commitCompletion(text);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.commitCompletion(text);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -222,7 +214,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#commitCorrection(CorrectionInfo)}.
+     * Invokes {@link IInputContext#commitCorrection(CorrectionInfo)}.
      *
      * @param correctionInfo {@code correctionInfo} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -230,9 +222,8 @@
      */
     @AnyThread
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
-        final InputConnectionCommand command = Commands.commitCorrection(correctionInfo);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.commitCorrection(correctionInfo);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -240,7 +231,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#setSelection(int, int)}.
+     * Invokes {@link IInputContext#setSelection(int, int)}.
      *
      * @param start {@code start} parameter to be passed.
      * @param end {@code start} parameter to be passed.
@@ -249,9 +240,8 @@
      */
     @AnyThread
     public boolean setSelection(int start, int end) {
-        final InputConnectionCommand command = Commands.setSelection(start, end);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.setSelection(start, end);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -259,7 +249,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#performEditorAction(int)}.
+     * Invokes {@link IInputContext#performEditorAction(int)}.
      *
      * @param actionCode {@code start} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -267,9 +257,8 @@
      */
     @AnyThread
     public boolean performEditorAction(int actionCode) {
-        final InputConnectionCommand command = Commands.performEditorAction(actionCode);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.performEditorAction(actionCode);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -277,7 +266,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#performContextMenuAction(int)}.
+     * Invokes {@link IInputContext#performContextMenuAction(id)}.
      *
      * @param id {@code id} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -285,9 +274,8 @@
      */
     @AnyThread
     public boolean performContextMenuAction(int id) {
-        final InputConnectionCommand command = Commands.performContextMenuAction(id);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.performContextMenuAction(id);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -295,7 +283,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#setComposingRegion(int, int)}.
+     * Invokes {@link IInputContext#setComposingRegion(int, int)}.
      *
      * @param start {@code id} parameter to be passed.
      * @param end {@code id} parameter to be passed.
@@ -304,9 +292,8 @@
      */
     @AnyThread
     public boolean setComposingRegion(int start, int end) {
-        final InputConnectionCommand command = Commands.setComposingRegion(start, end);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.setComposingRegion(start, end);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -314,8 +301,7 @@
     }
 
     /**
-     * Implements
-     * {@link android.view.inputmethod.InputConnection#setComposingText(CharSequence, int)}.
+     * Invokes {@link IInputContext#setComposingText(CharSequence, int)}.
      *
      * @param text {@code text} parameter to be passed.
      * @param newCursorPosition {@code newCursorPosition} parameter to be passed.
@@ -324,9 +310,8 @@
      */
     @AnyThread
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
-        final InputConnectionCommand command = Commands.setComposingText(text, newCursorPosition);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.setComposingText(text, newCursorPosition);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -334,16 +319,15 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#finishComposingText()}.
+     * Invokes {@link IInputContext#finishComposingText()}.
      *
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
      *         {@code false} otherwise.
      */
     @AnyThread
     public boolean finishComposingText() {
-        final InputConnectionCommand command = Commands.finishComposingText();
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.finishComposingText();
             return true;
         } catch (RemoteException e) {
             return false;
@@ -351,16 +335,15 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#beginBatchEdit()}.
+     * Invokes {@link IInputContext#beginBatchEdit()}.
      *
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
      *         {@code false} otherwise.
      */
     @AnyThread
     public boolean beginBatchEdit() {
-        final InputConnectionCommand command = Commands.beginBatchEdit();
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.beginBatchEdit();
             return true;
         } catch (RemoteException e) {
             return false;
@@ -368,16 +351,15 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#endBatchEdit()}.
+     * Invokes {@link IInputContext#endBatchEdit()}.
      *
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
      *         {@code false} otherwise.
      */
     @AnyThread
     public boolean endBatchEdit() {
-        final InputConnectionCommand command = Commands.endBatchEdit();
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.endBatchEdit();
             return true;
         } catch (RemoteException e) {
             return false;
@@ -385,7 +367,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#sendKeyEvent(KeyEvent)}.
+     * Invokes {@link IInputContext#sendKeyEvent(KeyEvent)}.
      *
      * @param event {@code event} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -393,9 +375,8 @@
      */
     @AnyThread
     public boolean sendKeyEvent(KeyEvent event) {
-        final InputConnectionCommand command = Commands.sendKeyEvent(event);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.sendKeyEvent(event);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -403,7 +384,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#clearMetaKeyStates(int)}.
+     * Invokes {@link IInputContext#clearMetaKeyStates(int)}.
      *
      * @param states {@code states} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -411,9 +392,8 @@
      */
     @AnyThread
     public boolean clearMetaKeyStates(int states) {
-        final InputConnectionCommand command = Commands.clearMetaKeyStates(states);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.clearMetaKeyStates(states);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -421,7 +401,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#deleteSurroundingText(int, int)}.
+     * Invokes {@link IInputContext#deleteSurroundingText(int, int)}.
      *
      * @param beforeLength {@code beforeLength} parameter to be passed.
      * @param afterLength {@code afterLength} parameter to be passed.
@@ -430,10 +410,8 @@
      */
     @AnyThread
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
-        final InputConnectionCommand command =
-                Commands.deleteSurroundingText(beforeLength, afterLength);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.deleteSurroundingText(beforeLength, afterLength);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -441,8 +419,7 @@
     }
 
     /**
-     * Implements
-     * {@link android.view.inputmethod.InputConnection#deleteSurroundingTextInCodePoints(int, int)}.
+     * Invokes {@link IInputContext#deleteSurroundingTextInCodePoints(int, int)}.
      *
      * @param beforeLength {@code beforeLength} parameter to be passed.
      * @param afterLength {@code afterLength} parameter to be passed.
@@ -451,10 +428,8 @@
      */
     @AnyThread
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
-        final InputConnectionCommand command =
-                Commands.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -462,16 +437,15 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#performSpellCheck()}.
+     * Invokes {@link IInputContext#performSpellCheck()}.
      *
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
      *         {@code false} otherwise.
      */
     @AnyThread
     public boolean performSpellCheck() {
-        final InputConnectionCommand command = Commands.performSpellCheck();
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.performSpellCheck();
             return true;
         } catch (RemoteException e) {
             return false;
@@ -479,8 +453,7 @@
     }
 
     /**
-     * Implements
-     * {@link android.view.inputmethod.InputConnection#performPrivateCommand(String, Bundle)}.
+     * Invokes {@link IInputContext#performPrivateCommand(String, Bundle)}.
      *
      * @param action {@code action} parameter to be passed.
      * @param data {@code data} parameter to be passed.
@@ -489,9 +462,8 @@
      */
     @AnyThread
     public boolean performPrivateCommand(String action, Bundle data) {
-        final InputConnectionCommand command = Commands.performPrivateCommand(action, data);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.performPrivateCommand(action, data);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -499,7 +471,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#requestCursorUpdates(int)}.
+     * Invokes {@link IInputContext#requestCursorUpdates(int, IIntResultCallback)}.
      *
      * @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
      * @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
@@ -509,10 +481,8 @@
     @NonNull
     public Completable.Boolean requestCursorUpdates(int cursorUpdateMode) {
         final Completable.Boolean value = Completable.createBoolean();
-        final InputConnectionCommand command =
-                Commands.requestCursorUpdates(cursorUpdateMode, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -520,8 +490,8 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#commitContent(InputContentInfo,
-     * int, Bundle)}.
+     * Invokes
+     * {@link IInputContext#commitContent(InputContentInfo, int, Bundle, IIntResultCallback)}.
      *
      * @param inputContentInfo {@code inputContentInfo} parameter to be passed.
      * @param flags {@code flags} parameter to be passed.
@@ -534,10 +504,8 @@
     public Completable.Boolean commitContent(InputContentInfo inputContentInfo, int flags,
             Bundle opts) {
         final Completable.Boolean value = Completable.createBoolean();
-        final InputConnectionCommand command =
-                Commands.commitContent(inputContentInfo, flags, opts, value);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
         } catch (RemoteException e) {
             value.onError(ThrowableHolder.of(e));
         }
@@ -545,7 +513,7 @@
     }
 
     /**
-     * Implements {@link android.view.inputmethod.InputConnection#setImeConsumesInput(boolean)}.
+     * Invokes {@link IInputContext#setImeConsumesInput(boolean)}.
      *
      * @param imeConsumesInput {@code imeConsumesInput} parameter to be passed.
      * @return {@code true} if the invocation is completed without {@link RemoteException}.
@@ -553,341 +521,11 @@
      */
     @AnyThread
     public boolean setImeConsumesInput(boolean imeConsumesInput) {
-        final InputConnectionCommand command = Commands.setImeConsumesInput(imeConsumesInput);
         try {
-            mIInputContext.doEdit(command);
+            mIInputContext.setImeConsumesInput(imeConsumesInput);
             return true;
         } catch (RemoteException e) {
             return false;
         }
     }
-
-    /**
-     * Defines the data packing rules from {@link android.view.inputmethod.InputConnection} API
-     * params into {@link InputConnectionCommand} fields.
-     *
-     * Rules need to be in sync with {@link com.android.internal.view.IInputConnectionWrapper} and
-     * {@link InputMethodDebug#dumpInputConnectionCommand(InputConnectionCommand)}.
-     */
-    private static final class Commands {
-        /**
-         * Not intended to be instantiated.
-         */
-        private Commands() { }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getTextAfterCursor(int n, int flags,
-                @NonNull Completable.CharSequence returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
-                    n,
-                    0,
-                    flags,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getTextBeforeCursor(int n, int flags,
-                @NonNull Completable.CharSequence returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
-                    n,
-                    0,
-                    flags,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getSelectedText(int flags,
-                @NonNull Completable.CharSequence returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_SELECTED_TEXT,
-                    0,
-                    0,
-                    flags,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getSurroundingText(int beforeLength, int afterLength,
-                int flags, @NonNull Completable.SurroundingText returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_SURROUNDING_TEXT,
-                    beforeLength,
-                    afterLength,
-                    flags,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getCursorCapsMode(int reqModes,
-                @NonNull Completable.Int returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
-                    reqModes,
-                    0,
-                    0,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand getExtractedText(@Nullable ExtractedTextRequest request,
-                int flags, @NonNull Completable.ExtractedText returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.GET_EXTRACTED_TEXT,
-                    0,
-                    0,
-                    flags,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.EXTRACTED_TEXT_REQUEST,
-                    request,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand commitText(@Nullable CharSequence text,
-                int newCursorPosition) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.COMMIT_TEXT,
-                    newCursorPosition,
-                    0,
-                    0,
-                    text);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand commitCompletion(@Nullable CompletionInfo text) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.COMMIT_COMPLETION,
-                    0,
-                    0,
-                    0,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.COMPLETION_INFO,
-                    text);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand commitCorrection(@Nullable CorrectionInfo correctionInfo) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.COMMIT_CORRECTION,
-                    0,
-                    0,
-                    0,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.CORRECTION_INFO,
-                    correctionInfo);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand setSelection(int start, int end) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.SET_SELECTION,
-                    start,
-                    end);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand performEditorAction(int actionCode) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.PERFORM_EDITOR_ACTION,
-                    actionCode);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand performContextMenuAction(int id) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
-                    id);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand setComposingRegion(int start, int end) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.SET_COMPOSING_REGION,
-                    start,
-                    end);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand setComposingText(@Nullable CharSequence text,
-                int newCursorPosition) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.SET_COMPOSING_TEXT,
-                    newCursorPosition,
-                    0,
-                    0,
-                    text);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand finishComposingText() {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.FINISH_COMPOSING_TEXT);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand beginBatchEdit() {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.BEGIN_BATCH_EDIT);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand endBatchEdit() {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.END_BATCH_EDIT);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand sendKeyEvent(@Nullable KeyEvent event) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.SEND_KEY_EVENT,
-                    0,
-                    0,
-                    0,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.KEY_EVENT,
-                    event);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand clearMetaKeyStates(int states) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.CLEAR_META_KEY_STATES,
-                    states);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand deleteSurroundingText(int beforeLength, int afterLength) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
-                    beforeLength,
-                    afterLength);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand deleteSurroundingTextInCodePoints(int beforeLength,
-                int afterLength) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
-                    beforeLength,
-                    afterLength);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand performSpellCheck() {
-            return InputConnectionCommand.create(InputConnectionCommandType.PERFORM_SPELL_CHECK);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand performPrivateCommand(@Nullable String action,
-                @Nullable Bundle data) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.PERFORM_PRIVATE_COMMAND,
-                    0,
-                    0,
-                    0,
-                    null,
-                    action,
-                    data);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand requestCursorUpdates(int cursorUpdateMode,
-                @NonNull Completable.Boolean returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
-                    cursorUpdateMode,
-                    0,
-                    0,
-                    null,
-                    null,
-                    null,
-                    InputConnectionCommand.ParcelableType.NULL,
-                    null,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand commitContent(@Nullable InputContentInfo inputContentInfo,
-                int flags, @Nullable Bundle opts, @NonNull Completable.Boolean returnValue) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.COMMIT_CONTENT,
-                    0,
-                    0,
-                    flags,
-                    null,
-                    null,
-                    opts,
-                    InputConnectionCommand.ParcelableType.INPUT_CONTENT_INFO,
-                    inputContentInfo,
-                    returnValue);
-        }
-
-        @AnyThread
-        @NonNull
-        static InputConnectionCommand setImeConsumesInput(boolean imeConsumesInput) {
-            return InputConnectionCommand.create(
-                    InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
-                    imeConsumesInput ? 1 : 0);
-        }
-    }
 }
diff --git a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
index d452e60..20ff83f 100644
--- a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
+++ b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java
@@ -40,9 +40,9 @@
  */
 class ImeTracingServerImpl extends ImeTracing {
     private static final String TRACE_DIRNAME = "/data/misc/wmtrace/";
-    private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.pb";
-    private static final String TRACE_FILENAME_IMS = "ime_trace_service.pb";
-    private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.pb";
+    private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.winscope";
+    private static final String TRACE_FILENAME_IMS = "ime_trace_service.winscope";
+    private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.winscope";
     private static final int BUFFER_CAPACITY = 4096 * 1024;
 
     // Needed for winscope to auto-detect the dump type. Explained further in
diff --git a/core/java/com/android/internal/view/InputBindResult.aidl b/core/java/com/android/internal/inputmethod/InputBindResult.aidl
similarity index 93%
rename from core/java/com/android/internal/view/InputBindResult.aidl
rename to core/java/com/android/internal/inputmethod/InputBindResult.aidl
index 7ff5c4e..4d4c22b 100644
--- a/core/java/com/android/internal/view/InputBindResult.aidl
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.internal.view;
+package com.android.internal.inputmethod;
 
 parcelable InputBindResult;
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java
similarity index 86%
rename from core/java/com/android/internal/view/InputBindResult.java
rename to core/java/com/android/internal/inputmethod/InputBindResult.java
index 92105b9..1357bac 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/inputmethod/InputBindResult.java
@@ -1,34 +1,34 @@
 /*
- * Copyright (C) 2007-2008 The Android Open 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
- * 
+ * Copyright (C) 2007 The Android Open 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.
+ * 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.view;
+package com.android.internal.inputmethod;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.annotation.IntDef;
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.UserHandle;
 import android.view.InputChannel;
 
+import com.android.internal.view.IInputMethodSession;
+
 import java.lang.annotation.Retention;
 
 /**
@@ -70,7 +70,7 @@
          *
          * <p>Some of fields such as {@link #channel} is not yet available.</p>
          *
-         * @see android.inputmethodservice.InputMethodService##onCreateInputMethodSessionInterface()
+         * @see android.inputmethodservice.InputMethodService#onCreateInputMethodSessionInterface()
          **/
         int SUCCESS_WAITING_IME_SESSION = 1;
         /**
@@ -129,7 +129,8 @@
          * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to
          * connect to an {@link android.inputmethodservice.InputMethodService} but failed.
          *
-         * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle)
+         * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int,
+         *      android.os.UserHandle)
          */
         int ERROR_IME_NOT_CONNECTED = 9;
         /**
@@ -175,7 +176,6 @@
     /**
      * The input method service.
      */
-    @UnsupportedAppUsage
     public final IInputMethodSession method;
 
     /**
@@ -188,26 +188,42 @@
      * no input method will be bound.
      */
     public final String id;
-    
+
     /**
      * Sequence number of this binding.
      */
     public final int sequence;
 
+    /**
+     * {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
+     */
     public final boolean isInputMethodSuppressingSpellChecker;
 
-    public InputBindResult(@ResultCode int _result,
-            IInputMethodSession _method, InputChannel _channel, String _id, int _sequence,
+    /**
+     * Creates a new instance of {@link InputBindResult}.
+     *
+     * @param result A result code defined in {@link ResultCode}.
+     * @param method {@link IInputMethodSession} to interact with the IME.
+     * @param channel {@link InputChannel} to forward input events to the IME.
+     * @param id The {@link String} representations of the IME, which is the same as
+     *           {@link android.view.inputmethod.InputMethodInfo#getId()} and
+     *           {@link android.content.ComponentName#flattenToShortString()}.
+     * @param sequence A sequence number of this binding.
+     * @param isInputMethodSuppressingSpellChecker {@code true} if the IME explicitly specifies
+     *                                             {@code suppressesSpellChecker="true"}.
+     */
+    public InputBindResult(@ResultCode int result,
+            IInputMethodSession method, InputChannel channel, String id, int sequence,
             boolean isInputMethodSuppressingSpellChecker) {
-        result = _result;
-        method = _method;
-        channel = _channel;
-        id = _id;
-        sequence = _sequence;
+        this.result = result;
+        this.method = method;
+        this.channel = channel;
+        this.id = id;
+        this.sequence = sequence;
         this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
     }
 
-    InputBindResult(Parcel source) {
+    private InputBindResult(Parcel source) {
         result = source.readInt();
         method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
         if (source.readInt() != 0) {
@@ -220,19 +236,19 @@
         isInputMethodSuppressingSpellChecker = source.readBoolean();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public String toString() {
-        return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
+        return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
                 + " sequence=" + sequence
                 + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
                 + "}";
     }
 
     /**
-     * Used to package this object into a {@link Parcel}.
-     *
-     * @param dest The {@link Parcel} to be written.
-     * @param flags The flags used for parceling.
+     * {@inheritDoc}
      */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
@@ -252,7 +268,6 @@
     /**
      * Used to make this class parcelable.
      */
-    @UnsupportedAppUsage
     public static final Parcelable.Creator<InputBindResult> CREATOR =
             new Parcelable.Creator<InputBindResult>() {
         @Override
@@ -266,12 +281,15 @@
         }
     };
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int describeContents() {
         return channel != null ? channel.describeContents() : 0;
     }
 
-    public String getResultString() {
+    private String getResultString() {
         switch (result) {
             case ResultCode.SUCCESS_WITH_IME_SESSION:
                 return "SUCCESS_WITH_IME_SESSION";
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.java b/core/java/com/android/internal/inputmethod/InputConnectionCommand.java
deleted file mode 100644
index acc1e40..0000000
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.AnyThread;
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.BadParcelableException;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputContentInfo;
-
-import java.lang.annotation.Retention;
-
-/**
- * Defines the command message to be used for IMEs to remotely invoke
- * {@link android.view.inputmethod.InputConnection} APIs in the IME client process then receive
- * results.
- */
-public final class InputConnectionCommand implements Parcelable {
-    private static final String TAG = "InputConnectionCommand";
-
-    @Retention(SOURCE)
-    @IntDef(value = {
-            ResultCallbackType.NULL,
-            ResultCallbackType.BOOLEAN,
-            ResultCallbackType.INT,
-            ResultCallbackType.CHAR_SEQUENCE,
-            ResultCallbackType.EXTRACTED_TEXT,
-            ResultCallbackType.SURROUNDING_TEXT,
-    })
-    @interface ResultCallbackType {
-        int NULL = 0;
-        int BOOLEAN = 1;
-        int INT = 2;
-        int CHAR_SEQUENCE = 3;
-        int EXTRACTED_TEXT = 4;
-        int SURROUNDING_TEXT = 5;
-    }
-
-    @Retention(SOURCE)
-    @IntDef(value = {
-            ParcelableType.NULL,
-            ParcelableType.EXTRACTED_TEXT_REQUEST,
-            ParcelableType.COMPLETION_INFO,
-            ParcelableType.CORRECTION_INFO,
-            ParcelableType.KEY_EVENT,
-            ParcelableType.INPUT_CONTENT_INFO,
-    })
-    @interface ParcelableType {
-        int NULL = 0;
-        int EXTRACTED_TEXT_REQUEST = 1;
-        int COMPLETION_INFO = 2;
-        int CORRECTION_INFO = 3;
-        int KEY_EVENT = 4;
-        int INPUT_CONTENT_INFO = 5;
-    }
-
-    @Retention(SOURCE)
-    @IntDef(flag = true, value = {
-            FieldMask.INT_ARG0,
-            FieldMask.INT_ARG1,
-            FieldMask.FLAGS,
-            FieldMask.CHAR_SEQUENCE,
-            FieldMask.STRING,
-            FieldMask.BUNDLE,
-            FieldMask.PARCELABLE,
-            FieldMask.CALLBACK,
-    })
-    @interface FieldMask {
-        int INT_ARG0 = 1 << 0;
-        int INT_ARG1 = 1 << 1;
-        int FLAGS = 1 << 2;
-        int CHAR_SEQUENCE = 1 << 3;
-        int STRING = 1 << 4;
-        int BUNDLE = 1 << 5;
-        int PARCELABLE = 1 << 6;
-        int CALLBACK = 1 << 7;
-    }
-
-    @IntRange(from = InputConnectionCommandType.FIRST_COMMAND,
-            to = InputConnectionCommandType.LAST_COMMAND)
-    @InputConnectionCommandType
-    public final int mCommandType;
-    public final int mIntArg0;
-    public final int mIntArg1;
-    public final int mFlags;
-    public final CharSequence mCharSequence;
-    public final String mString;
-    public final Bundle mBundle;
-    @ParcelableType
-    public final int mParcelableType;
-    public final Parcelable mParcelable;
-    @ResultCallbackType
-    public final int mResultCallbackType;
-    public final IBinder mResultCallback;
-
-    private InputConnectionCommand(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type, int intArg0, int intArg1, int flags,
-            @Nullable CharSequence charSequence, @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @ResultCallbackType int resultCallbackType, @Nullable IBinder resultCallback) {
-        if (type < InputConnectionCommandType.FIRST_COMMAND
-                || InputConnectionCommandType.LAST_COMMAND < type) {
-            throw new IllegalArgumentException("Unknown type=" + type);
-        }
-        mCommandType = type;
-        mIntArg0 = intArg0;
-        mIntArg1 = intArg1;
-        mFlags = flags;
-        mCharSequence = charSequence;
-        mString = string;
-        mBundle = bundle;
-        mParcelableType = parcelableType;
-        mParcelable = parcelable;
-        mResultCallbackType = resultCallbackType;
-        mResultCallback = resultCallback;
-    }
-
-    /**
-     * Creates {@link InputConnectionCommand} with the given {@link InputConnectionCommandType}.
-     *
-     * @param type {@link InputConnectionCommandType} to be set.
-     * @return An {@link InputConnectionCommand} that is initialized with {@code type}.
-     */
-    @NonNull
-    public static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type) {
-        return create(type, 0);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type, int intArg0) {
-        return create(type, intArg0, 0);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type, int intArg0, int intArg1) {
-        return create(type, intArg0, intArg1, 0, null);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type, int intArg0,
-            int intArg1, int flags, @Nullable CharSequence charSequence) {
-        return create(type, intArg0, intArg1, flags, charSequence, null, null);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle) {
-        return create(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, ParcelableType.NULL, null);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable, ResultCallbackType.NULL, null);
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @NonNull Completable.Boolean returnValue) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable,
-                ResultCallbackType.BOOLEAN, ResultCallbacks.of(returnValue));
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @NonNull Completable.Int returnValue) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable,
-                ResultCallbackType.INT, ResultCallbacks.of(returnValue));
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @NonNull Completable.CharSequence returnValue) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable,
-                ResultCallbackType.CHAR_SEQUENCE, ResultCallbacks.of(returnValue));
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @NonNull Completable.ExtractedText returnValue) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable,
-                ResultCallbackType.EXTRACTED_TEXT, ResultCallbacks.of(returnValue));
-    }
-
-    @NonNull
-    static InputConnectionCommand create(
-            @IntRange(
-                    from = InputConnectionCommandType.FIRST_COMMAND,
-                    to = InputConnectionCommandType.LAST_COMMAND)
-            @InputConnectionCommandType int type,
-            int intArg0, int intArg1, int flags, @Nullable CharSequence charSequence,
-            @Nullable String string, @Nullable Bundle bundle,
-            @ParcelableType int parcelableType, @Nullable Parcelable parcelable,
-            @NonNull Completable.SurroundingText returnValue) {
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable,
-                ResultCallbackType.SURROUNDING_TEXT, ResultCallbacks.of(returnValue));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @AnyThread
-    @Override
-    public int describeContents() {
-        int result = 0;
-        if (mBundle != null) {
-            result |= mBundle.describeContents();
-        }
-        if (mParcelable != null) {
-            result |= mParcelable.describeContents();
-        }
-        // Here we assume other objects will never contain FDs to be parcelled.
-        return result;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @AnyThread
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mCommandType);
-
-        @FieldMask final int fieldMask = getFieldMask();
-        dest.writeInt(fieldMask);
-        if ((fieldMask & FieldMask.INT_ARG0) != 0) {
-            dest.writeInt(mIntArg0);
-        }
-        if ((fieldMask & FieldMask.INT_ARG1) != 0) {
-            dest.writeInt(mIntArg1);
-        }
-        if ((fieldMask & FieldMask.FLAGS) != 0) {
-            dest.writeInt(mFlags);
-        }
-        if ((fieldMask & FieldMask.CHAR_SEQUENCE) != 0) {
-            TextUtils.writeToParcel(mCharSequence, dest, flags);
-        }
-        if ((fieldMask & FieldMask.STRING) != 0) {
-            dest.writeString(mString);
-        }
-        if ((fieldMask & FieldMask.BUNDLE) != 0) {
-            dest.writeBundle(mBundle);
-        }
-        if ((fieldMask & FieldMask.PARCELABLE) != 0) {
-            dest.writeInt(mParcelableType);
-            dest.writeTypedObject(mParcelable, flags);
-        }
-        if ((fieldMask & FieldMask.CALLBACK) != 0) {
-            dest.writeInt(mResultCallbackType);
-            dest.writeStrongBinder(mResultCallback);
-        }
-    }
-
-    @FieldMask
-    @AnyThread
-    private int getFieldMask() {
-        return (mIntArg0 != 0 ? FieldMask.INT_ARG0 : 0)
-                | (mIntArg1 != 0 ? FieldMask.INT_ARG1 : 0)
-                | (mFlags != 0 ? FieldMask.FLAGS : 0)
-                | (mCharSequence != null ? FieldMask.CHAR_SEQUENCE : 0)
-                | (mString != null ? FieldMask.STRING : 0)
-                | (mBundle != null ? FieldMask.BUNDLE : 0)
-                | (mParcelableType != ParcelableType.NULL ? FieldMask.PARCELABLE : 0)
-                | (mResultCallbackType != ResultCallbackType.NULL ? FieldMask.CALLBACK : 0);
-    }
-
-
-    /**
-     * A utility method to unparcel {@link InputConnectionCommand} from the given {@link Parcel}.
-     *
-     * <p>When this method throws any {@link RuntimeException} or its derived class, notably
-     * {@link BadParcelableException}, {@code source} is considered to be in an unexpected state and
-     * unsafe to continue reading any subsequent data.</p>
-     *
-     * @param source {@link Parcel} to read the data from.
-     * @return {@link InputConnectionCommand} that is parcelled from {@code source}.
-     */
-    @AnyThread
-    @NonNull
-    private static InputConnectionCommand createFromParcel(@NonNull Parcel source) {
-        final int type = source.readInt();
-        if (type < InputConnectionCommandType.FIRST_COMMAND
-                || InputConnectionCommandType.LAST_COMMAND < type) {
-            throw new BadParcelableException("Invalid InputConnectionCommandType=" + type);
-        }
-
-        @FieldMask final int fieldMask = source.readInt();
-        final int intArg0 = (fieldMask & FieldMask.INT_ARG0) != 0 ? source.readInt() : 0;
-        final int intArg1 = (fieldMask & FieldMask.INT_ARG1) != 0 ? source.readInt() : 0;
-        final int flags = (fieldMask & FieldMask.FLAGS) != 0 ? source.readInt() : 0;
-        final CharSequence charSequence = (fieldMask & FieldMask.CHAR_SEQUENCE) != 0
-                ? TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source) : null;
-        final String string = (fieldMask & FieldMask.STRING) != 0 ? source.readString() : null;
-        final Bundle bundle = (fieldMask & FieldMask.BUNDLE) != 0 ? source.readBundle() : null;
-
-        @ParcelableType final int parcelableType;
-        final Parcelable parcelable;
-        if ((fieldMask & FieldMask.PARCELABLE) != 0) {
-            parcelableType = source.readInt();
-            switch (parcelableType) {
-                case ParcelableType.EXTRACTED_TEXT_REQUEST:
-                    parcelable = source.readTypedObject(ExtractedTextRequest.CREATOR);
-                    break;
-                case ParcelableType.COMPLETION_INFO:
-                    parcelable = source.readTypedObject(CompletionInfo.CREATOR);
-                    break;
-                case ParcelableType.CORRECTION_INFO:
-                    parcelable = source.readTypedObject(CorrectionInfo.CREATOR);
-                    break;
-                case ParcelableType.KEY_EVENT:
-                    parcelable = source.readTypedObject(KeyEvent.CREATOR);
-                    break;
-                case ParcelableType.INPUT_CONTENT_INFO:
-                    parcelable = source.readTypedObject(InputContentInfo.CREATOR);
-                    break;
-                default:
-                    throw new BadParcelableException(
-                            "Invalid InputConnectionCommand.ParcelableType=" + parcelableType);
-            }
-        } else {
-            parcelableType = ParcelableType.NULL;
-            parcelable = null;
-        }
-        @ResultCallbackType final int resultCallbackType;
-        final IBinder resultCallback;
-        if ((fieldMask & FieldMask.CALLBACK) != 0) {
-            resultCallbackType = source.readInt();
-            switch (resultCallbackType) {
-                case ResultCallbackType.BOOLEAN:
-                case ResultCallbackType.INT:
-                case ResultCallbackType.CHAR_SEQUENCE:
-                case ResultCallbackType.EXTRACTED_TEXT:
-                case ResultCallbackType.SURROUNDING_TEXT:
-                    resultCallback = source.readStrongBinder();
-                    break;
-                default:
-                    throw new BadParcelableException(
-                            "Invalid InputConnectionCommand.ResultCallbackType="
-                                    + resultCallbackType);
-            }
-        } else {
-            resultCallbackType = ResultCallbackType.NULL;
-            resultCallback = null;
-        }
-        return new InputConnectionCommand(type, intArg0, intArg1, flags, charSequence, string,
-                bundle, parcelableType, parcelable, resultCallbackType, resultCallback);
-    }
-
-    /**
-     * Used to make this class parcelable.
-     */
-    public static final Parcelable.Creator<InputConnectionCommand> CREATOR =
-            new Parcelable.Creator<InputConnectionCommand>() {
-                @AnyThread
-                @NonNull
-                @Override
-                public InputConnectionCommand createFromParcel(Parcel source) {
-                    return InputConnectionCommand.createFromParcel(source);
-                }
-
-                @AnyThread
-                @NonNull
-                @Override
-                public InputConnectionCommand[] newArray(int size) {
-                    return new InputConnectionCommand[size];
-                }
-            };
-}
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java b/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java
deleted file mode 100644
index 1eb0101..0000000
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommandType.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-
-@Retention(SOURCE)
-@IntDef(value = {
-        InputConnectionCommandType.BEGIN_BATCH_EDIT,
-        InputConnectionCommandType.CLEAR_META_KEY_STATES,
-        InputConnectionCommandType.COMMIT_COMPLETION,
-        InputConnectionCommandType.COMMIT_CONTENT,
-        InputConnectionCommandType.COMMIT_CORRECTION,
-        InputConnectionCommandType.COMMIT_TEXT,
-        InputConnectionCommandType.DELETE_SURROUNDING_TEXT,
-        InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
-        InputConnectionCommandType.END_BATCH_EDIT,
-        InputConnectionCommandType.FINISH_COMPOSING_TEXT,
-        InputConnectionCommandType.GET_CURSOR_CAPS_MODE,
-        InputConnectionCommandType.GET_EXTRACTED_TEXT,
-        InputConnectionCommandType.GET_SELECTED_TEXT,
-        InputConnectionCommandType.GET_SURROUNDING_TEXT,
-        InputConnectionCommandType.GET_TEXT_AFTER_CURSOR,
-        InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR,
-        InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION,
-        InputConnectionCommandType.PERFORM_EDITOR_ACTION,
-        InputConnectionCommandType.PERFORM_SPELL_CHECK,
-        InputConnectionCommandType.REQUEST_CURSOR_UPDATES,
-        InputConnectionCommandType.SEND_KEY_EVENT,
-        InputConnectionCommandType.SET_COMPOSING_REGION,
-        InputConnectionCommandType.SET_COMPOSING_TEXT,
-        InputConnectionCommandType.SET_IME_CONSUMES_INPUT,
-        InputConnectionCommandType.SET_SELECTION,
-})
-public @interface InputConnectionCommandType {
-    int FIRST_COMMAND = 1;
-
-    int BEGIN_BATCH_EDIT = FIRST_COMMAND;
-    int CLEAR_META_KEY_STATES = 2;
-    int COMMIT_COMPLETION = 3;
-    int COMMIT_CONTENT = 4;
-    int COMMIT_CORRECTION = 5;
-    int COMMIT_TEXT = 6;
-    int DELETE_SURROUNDING_TEXT = 7;
-    int DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 8;
-    int END_BATCH_EDIT = 9;
-    int FINISH_COMPOSING_TEXT = 10;
-    int GET_CURSOR_CAPS_MODE = 11;
-    int GET_EXTRACTED_TEXT = 12;
-    int GET_SELECTED_TEXT = 13;
-    int GET_SURROUNDING_TEXT = 14;
-    int GET_TEXT_AFTER_CURSOR = 15;
-    int GET_TEXT_BEFORE_CURSOR = 16;
-    int PERFORM_CONTEXT_MENU_ACTION = 17;
-    int PERFORM_EDITOR_ACTION = 18;
-    int PERFORM_SPELL_CHECK = 19;
-    int PERFORM_PRIVATE_COMMAND = 20;
-    int REQUEST_CURSOR_UPDATES = 21;
-    int SEND_KEY_EVENT = 22;
-    int SET_COMPOSING_REGION = 23;
-    int SET_COMPOSING_TEXT = 24;
-    int SET_IME_CONSUMES_INPUT = 25;
-    int SET_SELECTION = 26;
-
-    int LAST_COMMAND = SET_SELECTION;
-}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 0475ed0..a00b993 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -18,7 +18,6 @@
 
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 
@@ -243,133 +242,6 @@
     }
 
     /**
-     * Converts {@link InputConnectionCommandType} to human readable {@link String}.
-     */
-    public static String inputConnectionCommandTypeToString(@InputConnectionCommandType int type) {
-        switch (type) {
-            case InputConnectionCommandType.BEGIN_BATCH_EDIT:
-                return "beginBatchEdit";
-            case InputConnectionCommandType.CLEAR_META_KEY_STATES:
-                return "clearMetaKeyStates";
-            case InputConnectionCommandType.COMMIT_COMPLETION:
-                return "commitCompletion";
-            case InputConnectionCommandType.COMMIT_CONTENT:
-                return "commitContent";
-            case InputConnectionCommandType.COMMIT_CORRECTION:
-                return "commitCorrection";
-            case InputConnectionCommandType.COMMIT_TEXT:
-                return "commitText";
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
-                return "deleteSurroundingText";
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
-                return "deleteSurroundingTextInCodePoints";
-            case InputConnectionCommandType.END_BATCH_EDIT:
-                return "endBatchEdit";
-            case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
-                return "finishComposingText";
-            case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
-                return "getCursorCapsMode";
-            case InputConnectionCommandType.GET_EXTRACTED_TEXT:
-                return "getExtractedText";
-            case InputConnectionCommandType.GET_SELECTED_TEXT:
-                return "getSelectedText";
-            case InputConnectionCommandType.GET_SURROUNDING_TEXT:
-                return "getSurroundingText";
-            case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
-                return "getTextAfterCursor";
-            case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
-                return "getTextBeforeCursor";
-            case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
-                return "performContextMenuAction";
-            case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
-                return "performEditorAction";
-            case InputConnectionCommandType.PERFORM_SPELL_CHECK:
-                return "performSpellCheck";
-            case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
-                return "requestCursorUpdates";
-            case InputConnectionCommandType.SEND_KEY_EVENT:
-                return "sendKeyEvent";
-            case InputConnectionCommandType.SET_COMPOSING_REGION:
-                return "setComposingRegion";
-            case InputConnectionCommandType.SET_COMPOSING_TEXT:
-                return "setComposingText";
-            case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
-                return "setImeConsumesInput";
-            case InputConnectionCommandType.SET_SELECTION:
-                return "setSelection";
-            default:
-                return "Unknown=" + type;
-        }
-    }
-
-    /**
-     * Converts {@link InputConnectionCommand} to human readable {@link String}.
-     */
-    @NonNull
-    public static String dumpInputConnectionCommand(@Nullable InputConnectionCommand command) {
-        if (command == null) {
-            return "null";
-        }
-        switch (command.mCommandType) {
-            case InputConnectionCommandType.BEGIN_BATCH_EDIT:
-                return "beginBatchEdit()";
-            case InputConnectionCommandType.CLEAR_META_KEY_STATES:
-                return "clearMetaKeyStates(" + command.mIntArg0 + ")";
-            case InputConnectionCommandType.COMMIT_COMPLETION:
-                return "commitCompletion(" + command.mParcelable + ")";
-            case InputConnectionCommandType.COMMIT_CONTENT:
-                return "commitContent(" + command.mParcelable + ", " + command.mFlags + ", "
-                        + command.mBundle + ")";
-            case InputConnectionCommandType.COMMIT_CORRECTION:
-                return "commitCorrection(" + command.mParcelable + ")";
-            case InputConnectionCommandType.COMMIT_TEXT:
-                return "commitText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT:
-                return "deleteSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS:
-                return "deleteSurroundingTextInCodePoints(" + command.mIntArg0 + ", "
-                        + command.mIntArg1 + ")";
-            case InputConnectionCommandType.END_BATCH_EDIT:
-                return "endBatchEdit()";
-            case InputConnectionCommandType.FINISH_COMPOSING_TEXT:
-                return "finishComposingText()";
-            case InputConnectionCommandType.GET_CURSOR_CAPS_MODE:
-                return "getCursorCapsMode(" + command.mIntArg0 + ")";
-            case InputConnectionCommandType.GET_EXTRACTED_TEXT:
-                return "getExtractedText(" + command.mParcelable + ", " + command.mFlags + ")";
-            case InputConnectionCommandType.GET_SELECTED_TEXT:
-                return "getSelectedText(" + command.mFlags + ")";
-            case InputConnectionCommandType.GET_SURROUNDING_TEXT:
-                return "getSurroundingText(" + command.mIntArg0 + ", " + command.mIntArg1 + ", "
-                        + command.mFlags + ")";
-            case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR:
-                return "getTextAfterCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
-            case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR:
-                return "getTextBeforeCursor(" + command.mIntArg0 + ", " + command.mFlags + ")";
-            case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION:
-                return "performContextMenuAction(" + command.mIntArg0 + ")";
-            case InputConnectionCommandType.PERFORM_EDITOR_ACTION:
-                return "performEditorAction(" + command.mIntArg0 + ")";
-            case InputConnectionCommandType.PERFORM_SPELL_CHECK:
-                return "performSpellCheck()";
-            case InputConnectionCommandType.REQUEST_CURSOR_UPDATES:
-                return "requestCursorUpdates(" + command.mIntArg0 + ")";
-            case InputConnectionCommandType.SEND_KEY_EVENT:
-                return "sendKeyEvent(" + command.mParcelable + ")";
-            case InputConnectionCommandType.SET_COMPOSING_REGION:
-                return "setComposingRegion(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
-            case InputConnectionCommandType.SET_COMPOSING_TEXT:
-                return "setComposingText(" + command.mCharSequence + ", " + command.mIntArg0 + ")";
-            case InputConnectionCommandType.SET_IME_CONSUMES_INPUT:
-                return "setImeConsumesInput(" + (command.mIntArg0 != 0) + ")";
-            case InputConnectionCommandType.SET_SELECTION:
-                return "setSelection(" + command.mIntArg0 + ", " + command.mIntArg1 + ")";
-            default:
-                return "unknown(type=" + command.mCommandType + ")";
-        }
-    }
-
-    /**
      * Return a fixed size string of the object.
      * TODO(b/151575861): Take & return with StringBuilder to make more memory efficient.
      */
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
new file mode 100644
index 0000000..0c27012
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DumpableInputConnection;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
+import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.SurroundingText;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.view.IInputContext;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Takes care of remote method invocations of {@link InputConnection} in the IME client side.
+ *
+ * <p>{@link android.inputmethodservice.RemoteInputConnection} code is executed in the IME process.
+ * It makes IInputContext binder calls under the hood. {@link RemoteInputConnectionImpl} receives
+ * {@link IInputContext} binder calls in the IME client (editor app) process, and forwards them to
+ * {@link InputConnection} that the IME client provided, on the {@link Looper} associated to the
+ * {@link InputConnection}.</p>
+ */
+public final class RemoteInputConnectionImpl extends IInputContext.Stub {
+    private static final String TAG = "RemoteInputConnectionImpl";
+    private static final boolean DEBUG = false;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private InputConnection mInputConnection;
+
+    @NonNull
+    private final Looper mLooper;
+    private final Handler mH;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private boolean mFinished = false;
+
+    private final InputMethodManager mParentInputMethodManager;
+    private final WeakReference<View> mServedView;
+
+    public RemoteInputConnectionImpl(@NonNull Looper looper,
+            @NonNull InputConnection inputConnection,
+            @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
+        mInputConnection = inputConnection;
+        mLooper = looper;
+        mH = new Handler(mLooper);
+        mParentInputMethodManager = inputMethodManager;
+        mServedView = new WeakReference<>(servedView);
+    }
+
+    /**
+     * @return {@link InputConnection} to which incoming IPCs will be dispatched.
+     */
+    @Nullable
+    private InputConnection getInputConnection() {
+        synchronized (mLock) {
+            return mInputConnection;
+        }
+    }
+
+    /**
+     * @return {@code true} until the target {@link InputConnection} receives
+     * {@link InputConnection#closeConnection()} as a result of {@link #deactivate()}.
+     */
+    public boolean isFinished() {
+        synchronized (mLock) {
+            return mFinished;
+        }
+    }
+
+    public boolean isActive() {
+        return mParentInputMethodManager.isActive() && !isFinished();
+    }
+
+    public View getServedView() {
+        return mServedView.get();
+    }
+
+    /**
+     * Called when this object needs to be permanently deactivated.
+     *
+     * <p>Multiple invocations will be simply ignored.</p>
+     */
+    public void deactivate() {
+        if (isFinished()) {
+            // This is a small performance optimization.  Still only the 1st call of
+            // reportFinish() will take effect.
+            return;
+        }
+        dispatch(() -> {
+            // Note that we do not need to worry about race condition here, because 1) mFinished is
+            // updated only inside this block, and 2) the code here is running on a Handler hence we
+            // assume multiple closeConnection() tasks will not be handled at the same time.
+            if (isFinished()) {
+                return;
+            }
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
+            try {
+                InputConnection ic = getInputConnection();
+                // Note we do NOT check isActive() here, because this is safe
+                // for an IME to call at any time, and we need to allow it
+                // through to clean up our state after the IME has switched to
+                // another client.
+                if (ic == null) {
+                    return;
+                }
+                @MissingMethodFlags
+                final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
+                if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+                    ic.closeConnection();
+                }
+            } finally {
+                synchronized (mLock) {
+                    mInputConnection = null;
+                    mFinished = true;
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+
+            // Notify the app that the InputConnection was closed.
+            final View servedView = mServedView.get();
+            if (servedView != null) {
+                final Handler handler = servedView.getHandler();
+                // The handler is null if the view is already detached. When that's the case, for
+                // now, we simply don't dispatch this callback.
+                if (handler != null) {
+                    if (DEBUG) {
+                        Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
+                    }
+                    if (handler.getLooper().isCurrentThread()) {
+                        servedView.onInputConnectionClosedInternal();
+                    } else {
+                        handler.post(servedView::onInputConnectionClosedInternal);
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public String toString() {
+        return "RemoteInputConnectionImpl{"
+                + "connection=" + getInputConnection()
+                + " finished=" + isFinished()
+                + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive()
+                + " mServedView=" + mServedView.get()
+                + "}";
+    }
+
+    /**
+     * Called by {@link InputMethodManager} to dump the editor state.
+     *
+     * @param proto {@link ProtoOutputStream} to which the editor state should be dumped.
+     * @param fieldId the ID to be passed to
+     *                {@link DumpableInputConnection#dumpDebug(ProtoOutputStream, long)}.
+     */
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        synchronized (mLock) {
+            // Check that the call is initiated in the target thread of the current InputConnection
+            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
+            // executed on this thread. Otherwise the messages are dispatched to the correct thread
+            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
+            // reasons.
+            if ((mInputConnection instanceof DumpableInputConnection)
+                    && mLooper.isCurrentThread()) {
+                ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId);
+            }
+        }
+    }
+
+    /**
+     * Invoke {@link InputConnection#reportFullscreenMode(boolean)} or schedule it on the target
+     * thread associated with {@link InputConnection#getHandler()}.
+     *
+     * @param enabled the parameter to be passed to
+     *                {@link InputConnection#reportFullscreenMode(boolean)}.
+     */
+    public void dispatchReportFullscreenMode(boolean enabled) {
+        dispatch(() -> {
+            final InputConnection ic = getInputConnection();
+            if (ic == null || !isActive()) {
+                return;
+            }
+            ic.reportFullscreenMode(enabled);
+        });
+    }
+
+    @Override
+    public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
+            try {
+                final InputConnection ic = getInputConnection();
+                final CharSequence result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+                    result = null;
+                } else {
+                    result = ic.getTextAfterCursor(length, flags);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(
+                            length, flags, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
+            try {
+                final InputConnection ic = getInputConnection();
+                final CharSequence result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+                    result = null;
+                } else {
+                    result = ic.getTextBeforeCursor(length, flags);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(
+                            length, flags, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
+            try {
+                final InputConnection ic = getInputConnection();
+                final CharSequence result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getSelectedText on inactive InputConnection");
+                    result = null;
+                } else {
+                    result = ic.getSelectedText(flags);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(
+                            flags, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getSelectedText", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getSelectedText()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void getSurroundingText(int beforeLength, int afterLength, int flags,
+            ISurroundingTextResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
+            try {
+                final InputConnection ic = getInputConnection();
+                final SurroundingText result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getSurroundingText on inactive InputConnection");
+                    result = null;
+                } else {
+                    result = ic.getSurroundingText(beforeLength, afterLength, flags);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
+                            beforeLength, afterLength, flags, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getSurroundingText()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
+            try {
+                final InputConnection ic = getInputConnection();
+                final int result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+                    result = 0;
+                } else {
+                    result = ic.getCursorCapsMode(reqModes);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(
+                            reqModes, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void getExtractedText(ExtractedTextRequest request, int flags,
+            IExtractedTextResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
+            try {
+                final InputConnection ic = getInputConnection();
+                final ExtractedText result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "getExtractedText on inactive InputConnection");
+                    result = null;
+                } else {
+                    result = ic.getExtractedText(request, flags);
+                }
+                if (ImeTracing.getInstance().isEnabled()) {
+                    final byte[] icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(
+                            request, flags, result);
+                    ImeTracing.getInstance().triggerClientDump(
+                            TAG + "#getExtractedText", mParentInputMethodManager, icProto);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to getExtractedText()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void commitText(CharSequence text, int newCursorPosition) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "commitText on inactive InputConnection");
+                    return;
+                }
+                ic.commitText(text, newCursorPosition);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void commitCompletion(CompletionInfo text) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "commitCompletion on inactive InputConnection");
+                    return;
+                }
+                ic.commitCompletion(text);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void commitCorrection(CorrectionInfo info) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "commitCorrection on inactive InputConnection");
+                    return;
+                }
+                ic.commitCorrection(info);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void setSelection(int start, int end) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "setSelection on inactive InputConnection");
+                    return;
+                }
+                ic.setSelection(start, end);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void performEditorAction(int id) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "performEditorAction on inactive InputConnection");
+                    return;
+                }
+                ic.performEditorAction(id);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void performContextMenuAction(int id) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+                    return;
+                }
+                ic.performContextMenuAction(id);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void setComposingRegion(int start, int end) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "setComposingRegion on inactive InputConnection");
+                    return;
+                }
+                ic.setComposingRegion(start, end);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void setComposingText(CharSequence text, int newCursorPosition) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "setComposingText on inactive InputConnection");
+                    return;
+                }
+                ic.setComposingText(text, newCursorPosition);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void finishComposingText() {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
+            try {
+                if (isFinished()) {
+                    // In this case, #finishComposingText() is guaranteed to be called already.
+                    // There should be no negative impact if we ignore this call silently.
+                    if (DEBUG) {
+                        Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+                    }
+                    return;
+                }
+                InputConnection ic = getInputConnection();
+                // Note we do NOT check isActive() here, because this is safe
+                // for an IME to call at any time, and we need to allow it
+                // through to clean up our state after the IME has switched to
+                // another client.
+                if (ic == null) {
+                    Log.w(TAG, "finishComposingText on inactive InputConnection");
+                    return;
+                }
+                ic.finishComposingText();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void sendKeyEvent(KeyEvent event) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+                    return;
+                }
+                ic.sendKeyEvent(event);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void clearMetaKeyStates(int states) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+                    return;
+                }
+                ic.clearMetaKeyStates(states);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void deleteSurroundingText(int beforeLength, int afterLength) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+                    return;
+                }
+                ic.deleteSurroundingText(beforeLength, afterLength);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT,
+                    "InputConnection#deleteSurroundingTextInCodePoints");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+                    return;
+                }
+                ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void beginBatchEdit() {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+                    return;
+                }
+                ic.beginBatchEdit();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void endBatchEdit() {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "endBatchEdit on inactive InputConnection");
+                    return;
+                }
+                ic.endBatchEdit();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void performSpellCheck() {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "performSpellCheck on inactive InputConnection");
+                    return;
+                }
+                ic.performSpellCheck();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void performPrivateCommand(String action, Bundle data) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "performPrivateCommand on inactive InputConnection");
+                    return;
+                }
+                ic.performPrivateCommand(action, data);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
+            try {
+                final InputConnection ic = getInputConnection();
+                final boolean result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+                    result = false;
+                } else {
+                    result = ic.requestCursorUpdates(cursorUpdateMode);
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
+            IBooleanResultCallback callback) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
+            try {
+                final InputConnection ic = getInputConnection();
+                final boolean result;
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "commitContent on inactive InputConnection");
+                    result = false;
+                } else {
+                    if (inputContentInfo == null || !inputContentInfo.validate()) {
+                        Log.w(TAG, "commitContent with invalid inputContentInfo="
+                                + inputContentInfo);
+                        result = false;
+                    } else {
+                        result = ic.commitContent(inputContentInfo, flags, opts);
+                    }
+                }
+                try {
+                    callback.onResult(result);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to return the result to commitContent()."
+                            + " result=" + result, e);
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    @Override
+    public void setImeConsumesInput(boolean imeConsumesInput) {
+        dispatch(() -> {
+            Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setImeConsumesInput");
+            try {
+                InputConnection ic = getInputConnection();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "setImeConsumesInput on inactive InputConnection");
+                    return;
+                }
+                ic.setImeConsumesInput(imeConsumesInput);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+            }
+        });
+    }
+
+    private void dispatch(@NonNull Runnable runnable) {
+        // If we are calling this from the target thread, then we can call right through.
+        // Otherwise, we need to send the message to the target thread.
+        if (mLooper.isCurrentThread()) {
+            runnable.run();
+            return;
+        }
+
+        mH.post(runnable);
+    }
+}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 8e7fae7..aa7142e 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -45,6 +45,7 @@
 import android.view.ViewRootImpl;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.jank.InteractionJankMonitor.Session;
 import com.android.internal.util.FrameworkStatsLog;
 
@@ -69,6 +70,7 @@
     static final int REASON_CANCEL_NORMAL = 16;
     static final int REASON_CANCEL_NOT_BEGUN = 17;
     static final int REASON_CANCEL_SAME_VSYNC = 18;
+    static final int REASON_CANCEL_TIMEOUT = 19;
 
     /** @hide */
     @IntDef({
@@ -97,6 +99,9 @@
     private final Handler mHandler;
     private final ChoreographerWrapper mChoreographer;
 
+    @VisibleForTesting
+    public final boolean mSurfaceOnly;
+
     private long mBeginVsyncId = INVALID_ID;
     private long mEndVsyncId = INVALID_ID;
     private boolean mMetricsFinalized;
@@ -136,71 +141,86 @@
     }
 
     public FrameTracker(@NonNull Session session, @NonNull Handler handler,
-            @NonNull ThreadedRendererWrapper renderer, @NonNull ViewRootWrapper viewRootWrapper,
+            @Nullable ThreadedRendererWrapper renderer, @Nullable ViewRootWrapper viewRootWrapper,
             @NonNull SurfaceControlWrapper surfaceControlWrapper,
             @NonNull ChoreographerWrapper choreographer,
-            @NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames,
-            int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) {
+            @Nullable FrameMetricsWrapper metrics,
+            int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis,
+            @Nullable FrameTrackerListener listener, @NonNull Configuration config) {
+        mSurfaceOnly = config.isSurfaceOnly();
         mSession = session;
-        mRendererWrapper = renderer;
-        mMetricsWrapper = metrics;
-        mViewRoot = viewRootWrapper;
+        mHandler = handler;
         mChoreographer = choreographer;
         mSurfaceControlWrapper = surfaceControlWrapper;
-        mHandler = handler;
-        mObserver = new HardwareRendererObserver(
-                this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/);
+
+        // HWUI instrumentation init.
+        mRendererWrapper = mSurfaceOnly ? null : renderer;
+        mMetricsWrapper = mSurfaceOnly ? null : metrics;
+        mViewRoot = mSurfaceOnly ? null : viewRootWrapper;
+        mObserver = mSurfaceOnly
+                ? null
+                : new HardwareRendererObserver(this, mMetricsWrapper.getTiming(),
+                        handler, /* waitForPresentTime= */ false);
+
         mTraceThresholdMissedFrames = traceThresholdMissedFrames;
         mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
         mListener = listener;
 
-        // If the surface isn't valid yet, wait until it's created.
-        if (viewRootWrapper.getSurfaceControl().isValid()) {
-            mSurfaceControl = viewRootWrapper.getSurfaceControl();
+        if (mSurfaceOnly) {
+            mSurfaceControl = config.getSurfaceControl();
+            mSurfaceChangedCallback = null;
+        } else {
+            // HWUI instrumentation init.
+            // If the surface isn't valid yet, wait until it's created.
+            if (mViewRoot.getSurfaceControl().isValid()) {
+                mSurfaceControl = mViewRoot.getSurfaceControl();
+                mSurfaceChangedCallback = null;
+            } else {
+                mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
+                    @Override
+                    public void surfaceCreated(SurfaceControl.Transaction t) {
+                        synchronized (FrameTracker.this) {
+                            if (mSurfaceControl == null) {
+                                mSurfaceControl = mViewRoot.getSurfaceControl();
+                                if (mBeginVsyncId != INVALID_ID) {
+                                    mSurfaceControlWrapper.addJankStatsListener(
+                                            FrameTracker.this, mSurfaceControl);
+                                    postTraceStartMarker();
+                                }
+                            }
+                        }
+                    }
+
+                    @Override
+                    public void surfaceReplaced(SurfaceControl.Transaction t) {
+                    }
+
+                    @Override
+                    public void surfaceDestroyed() {
+
+                        // Wait a while to give the system a chance for the remaining
+                        // frames to arrive, then force finish the session.
+                        mHandler.postDelayed(() -> {
+                            synchronized (FrameTracker.this) {
+                                if (DEBUG) {
+                                    Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
+                                            + ", finalized=" + mMetricsFinalized
+                                            + ", info=" + mJankInfos.size()
+                                            + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
+                                }
+                                if (!mMetricsFinalized) {
+                                    end(REASON_END_SURFACE_DESTROYED);
+                                    finish(mJankInfos.size() - 1);
+                                }
+                            }
+                        }, 50);
+                    }
+                };
+                // This callback has a reference to FrameTracker,
+                // remember to remove it to avoid leakage.
+                mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback);
+            }
         }
-        mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
-            @Override
-            public void surfaceCreated(SurfaceControl.Transaction t) {
-                synchronized (FrameTracker.this) {
-                    if (mSurfaceControl == null) {
-                        mSurfaceControl = viewRootWrapper.getSurfaceControl();
-                        if (mBeginVsyncId != INVALID_ID) {
-                            mSurfaceControlWrapper.addJankStatsListener(
-                                    FrameTracker.this, mSurfaceControl);
-                            postTraceStartMarker();
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public void surfaceReplaced(SurfaceControl.Transaction t) {
-            }
-
-            @Override
-            public void surfaceDestroyed() {
-
-                // Wait a while to give the system a chance for the remaining frames to arrive, then
-                // force finish the session.
-                mHandler.postDelayed(() -> {
-                    synchronized (FrameTracker.this) {
-                        if (DEBUG) {
-                            Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
-                                    + ", finalized=" + mMetricsFinalized
-                                    + ", info=" + mJankInfos.size()
-                                    + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
-                        }
-                        if (!mMetricsFinalized) {
-                            end(REASON_END_SURFACE_DESTROYED);
-                            finish(mJankInfos.size() - 1);
-                        }
-                    }
-                }, 50);
-            }
-        };
-
-        // This callback has a reference to FrameTracker, remember to remove it to avoid leakage.
-        viewRootWrapper.addSurfaceChangedCallback(mSurfaceChangedCallback);
     }
 
     /**
@@ -208,16 +228,16 @@
      */
     public synchronized void begin() {
         mBeginVsyncId = mChoreographer.getVsyncId() + 1;
-        if (mSurfaceControl != null) {
-            postTraceStartMarker();
-        }
-        mRendererWrapper.addObserver(mObserver);
         if (DEBUG) {
             Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId);
         }
         if (mSurfaceControl != null) {
+            postTraceStartMarker();
             mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
         }
+        if (!mSurfaceOnly) {
+            mRendererWrapper.addObserver(mObserver);
+        }
         if (mListener != null) {
             mListener.onCujEvents(mSession, ACTION_SESSION_BEGIN);
         }
@@ -273,11 +293,12 @@
      * Cancel the trace session of the CUJ.
      */
     public synchronized void cancel(@Reasons int reason) {
+        mCancelled = true;
+
         // We don't need to end the trace section if it never begun.
         if (mTracingStarted) {
             Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
         }
-        mCancelled = true;
 
         // Always remove the observers in cancel call to avoid leakage.
         removeObservers();
@@ -377,7 +398,7 @@
         for (int i = mJankInfos.size() - 1; i >= 0; i--) {
             JankInfo info = mJankInfos.valueAt(i);
             if (info.frameVsyncId >= mEndVsyncId) {
-                if (info.hwuiCallbackFired && info.surfaceControlCallbackFired) {
+                if (isLastIndexCandidate(info)) {
                     lastIndex = i;
                 }
             } else {
@@ -395,6 +416,12 @@
         finish(indexOnOrAfterEnd);
     }
 
+    private boolean isLastIndexCandidate(JankInfo info) {
+        return mSurfaceOnly
+                ? info.surfaceControlCallbackFired
+                : info.hwuiCallbackFired && info.surfaceControlCallbackFired;
+    }
+
     private void finish(int indexOnOrAfterEnd) {
 
         mMetricsFinalized = true;
@@ -410,7 +437,8 @@
 
         for (int i = 0; i <= indexOnOrAfterEnd; i++) {
             JankInfo info = mJankInfos.valueAt(i);
-            if (info.isFirstFrame) {
+            final boolean isFirstDrawn = !mSurfaceOnly && info.isFirstFrame;
+            if (isFirstDrawn) {
                 continue;
             }
             if (info.surfaceControlCallbackFired) {
@@ -435,11 +463,11 @@
                 }
                 // TODO (b/174755489): Early latch currently gets fired way too often, so we have
                 // to ignore it for now.
-                if (!info.hwuiCallbackFired) {
+                if (!mSurfaceOnly && !info.hwuiCallbackFired) {
                     Log.w(TAG, "Missing HWUI jank callback for vsyncId: " + info.frameVsyncId);
                 }
             }
-            if (info.hwuiCallbackFired) {
+            if (!mSurfaceOnly && info.hwuiCallbackFired) {
                 maxFrameTimeNanos = Math.max(info.totalDurationNanos, maxFrameTimeNanos);
                 if (!info.surfaceControlCallbackFired) {
                     Log.w(TAG, "Missing SF jank callback for vsyncId: " + info.frameVsyncId);
@@ -462,7 +490,7 @@
         // Trigger perfetto if necessary.
         boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
                 && missedFramesCount >= mTraceThresholdMissedFrames;
-        boolean overFrameTimeThreshold = mTraceThresholdFrameTimeMillis != -1
+        boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1
                 && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND;
         if (overMissedFramesThreshold || overFrameTimeThreshold) {
             triggerPerfetto();
@@ -473,7 +501,7 @@
                     mSession.getStatsdInteractionType(),
                     totalFramesCount,
                     missedFramesCount,
-                    maxFrameTimeNanos,
+                    maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */
                     missedSfFramesCount,
                     missedAppFramesCount);
             if (mListener != null) {
@@ -496,10 +524,13 @@
      */
     @VisibleForTesting
     public void removeObservers() {
-        mRendererWrapper.removeObserver(mObserver);
         mSurfaceControlWrapper.removeJankStatsListener(this);
-        if (mSurfaceChangedCallback != null) {
-            mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback);
+        if (!mSurfaceOnly) {
+            // HWUI part.
+            mRendererWrapper.removeObserver(mObserver);
+            if (mSurfaceChangedCallback != null) {
+                mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index aabcd7f..aae6f50 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -18,11 +18,11 @@
 
 import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
 
-import static com.android.internal.jank.FrameTracker.ChoreographerWrapper;
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
 import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NOT_BEGUN;
+import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
 import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
-import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
+import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -41,6 +41,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
@@ -58,6 +59,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -72,11 +74,15 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Choreographer;
+import android.view.SurfaceControl;
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
 import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
 import com.android.internal.jank.FrameTracker.FrameTrackerListener;
+import com.android.internal.jank.FrameTracker.Reasons;
+import com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
 import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
 import com.android.internal.jank.FrameTracker.ViewRootWrapper;
 import com.android.internal.util.PerfettoTrigger;
@@ -103,7 +109,7 @@
     private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
 
     private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
-    private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
+    private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L);
     private static final String SETTINGS_ENABLED_KEY = "enabled";
     private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
     private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =
@@ -163,6 +169,8 @@
     public static final int CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE = 32;
     public static final int CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON = 33;
     public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34;
+    public static final int CUJ_PIP_TRANSITION = 35;
+    public static final int CUJ_WALLPAPER_TRANSITION = 36;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -206,6 +214,8 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON,
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION,
+            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION,
     };
 
     private static volatile InteractionJankMonitor sInstance;
@@ -213,10 +223,10 @@
     private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
             this::updateProperties;
 
-    private FrameMetricsWrapper mMetrics;
-    private SparseArray<FrameTracker> mRunningTrackers;
-    private SparseArray<Runnable> mTimeoutActions;
-    private HandlerThread mWorker;
+    private final FrameMetricsWrapper mMetrics;
+    private final SparseArray<FrameTracker> mRunningTrackers;
+    private final SparseArray<Runnable> mTimeoutActions;
+    private final HandlerThread mWorker;
 
     private boolean mEnabled = DEFAULT_ENABLED;
     private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
@@ -260,6 +270,8 @@
             CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE,
             CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON,
             CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
+            CUJ_PIP_TRANSITION,
+            CUJ_WALLPAPER_TRANSITION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -310,24 +322,31 @@
     }
 
     /**
-     * Create a {@link FrameTracker} instance.
+     * Creates a {@link FrameTracker} instance.
      *
+     * @param config the config used in instrumenting
      * @param session the session associates with this tracker
      * @return instance of the FrameTracker
      */
     @VisibleForTesting
-    public FrameTracker createFrameTracker(Configuration conf, Session session) {
-        final View v = conf.mView;
-        final Context c = v.getContext().getApplicationContext();
-        final ThreadedRendererWrapper r = new ThreadedRendererWrapper(v.getThreadedRenderer());
-        final ViewRootWrapper vr = new ViewRootWrapper(v.getViewRootImpl());
-        final SurfaceControlWrapper sc = new SurfaceControlWrapper();
-        final ChoreographerWrapper cg = new ChoreographerWrapper(Choreographer.getInstance());
+    public FrameTracker createFrameTracker(Configuration config, Session session) {
+        final View view = config.mView;
+        final ThreadedRendererWrapper threadedRenderer =
+                view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer());
+        final ViewRootWrapper viewRoot =
+                view == null ? null : new ViewRootWrapper(view.getViewRootImpl());
+
+        final SurfaceControlWrapper surfaceControl = new SurfaceControlWrapper();
+        final ChoreographerWrapper choreographer =
+                new ChoreographerWrapper(Choreographer.getInstance());
 
         synchronized (this) {
-            FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(c, act, s);
-            return new FrameTracker(session, mWorker.getThreadHandler(), r, vr, sc, cg, mMetrics,
-                    mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener);
+            FrameTrackerListener eventsListener =
+                    (s, act) -> handleCujEvents(config.getContext(), act, s);
+            return new FrameTracker(session, mWorker.getThreadHandler(),
+                    threadedRenderer, viewRoot, surfaceControl, choreographer, mMetrics,
+                    mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
+                    eventsListener, config);
         }
     }
 
@@ -376,7 +395,7 @@
     }
 
     /**
-     * Begin a trace session.
+     * Begins a trace session.
      *
      * @param v an attached view.
      * @param cujType the specific {@link InteractionJankMonitor.CujType}.
@@ -385,8 +404,7 @@
     public boolean begin(View v, @CujType int cujType) {
         try {
             return beginInternal(
-                    new Configuration.Builder(cujType)
-                            .setView(v)
+                    Configuration.Builder.withView(cujType, v)
                             .build());
         } catch (IllegalArgumentException ex) {
             Log.d(TAG, "Build configuration failed!", ex);
@@ -395,7 +413,7 @@
     }
 
     /**
-     * Begin a trace session.
+     * Begins a trace session.
      *
      * @param builder the builder of the configurations for instrumenting the CUJ.
      * @return boolean true if the tracker is started successfully, false otherwise.
@@ -431,48 +449,60 @@
             tracker.begin();
 
             // Cancel the trace if we don't get an end() call in specified duration.
-            Runnable timeoutAction = () -> cancel(cujType);
-            mTimeoutActions.put(cujType, timeoutAction);
-            mWorker.getThreadHandler().postDelayed(timeoutAction, conf.mTimeout);
+            scheduleTimeoutAction(
+                    cujType, conf.mTimeout, () -> cancel(cujType, REASON_CANCEL_TIMEOUT));
             return true;
         }
     }
 
     /**
-     * End a trace session.
+     * Schedules a timeout action.
+     * @param cuj cuj type
+     * @param timeout duration to timeout
+     * @param action action once timeout
+     */
+    @VisibleForTesting
+    public void scheduleTimeoutAction(@CujType int cuj, long timeout, Runnable action) {
+        mTimeoutActions.put(cuj, action);
+        mWorker.getThreadHandler().postDelayed(action, timeout);
+    }
+
+    /**
+     * Ends a trace session.
      *
      * @param cujType the specific {@link InteractionJankMonitor.CujType}.
      * @return boolean true if the tracker is ended successfully, false otherwise.
      */
     public boolean end(@CujType int cujType) {
-        //TODO (163505250): This should be no-op if not in droid food rom.
         synchronized (this) {
-
             // remove the timeout action first.
             removeTimeout(cujType);
             FrameTracker tracker = getTracker(cujType);
             // Skip this call since we haven't started a trace yet.
             if (tracker == null) return false;
-            tracker.end(FrameTracker.REASON_END_NORMAL);
+            tracker.end(REASON_END_NORMAL);
             removeTracker(cujType);
             return true;
         }
     }
 
     /**
-     * Cancel the trace session.
+     * Cancels the trace session.
      *
      * @return boolean true if the tracker is cancelled successfully, false otherwise.
      */
     public boolean cancel(@CujType int cujType) {
-        //TODO (163505250): This should be no-op if not in droid food rom.
+        return cancel(cujType, REASON_CANCEL_NORMAL);
+    }
+
+    boolean cancel(@CujType int cujType, @Reasons int reason) {
         synchronized (this) {
             // remove the timeout action first.
             removeTimeout(cujType);
             FrameTracker tracker = getTracker(cujType);
             // Skip this call since we haven't started a trace yet.
             if (tracker == null) return false;
-            tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+            tracker.cancel(reason);
             removeTracker(cujType);
             return true;
         }
@@ -509,7 +539,7 @@
     }
 
     /**
-     * Trigger the perfetto daemon to collect and upload data.
+     * Triggers the perfetto daemon to collect and upload data.
      */
     @VisibleForTesting
     public void trigger(Session session) {
@@ -608,6 +638,10 @@
                 return "SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON";
             case CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP:
                 return "STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP";
+            case CUJ_PIP_TRANSITION:
+                return "PIP_TRANSITION";
+            case CUJ_WALLPAPER_TRANSITION:
+                return "WALLPAPER_TRANSITION";
         }
         return "UNKNOWN";
     }
@@ -618,32 +652,64 @@
      */
     public static class Configuration {
         private final View mView;
+        private final Context mContext;
         private final long mTimeout;
         private final String mTag;
+        private final boolean mSurfaceOnly;
+        private final SurfaceControl mSurfaceControl;
         private final @CujType int mCujType;
 
         /**
-         * A builder for building Configuration. <br/>
+         * A builder for building Configuration. {@link #setView(View)} is essential
+         * if {@link #setSurfaceOnly(boolean)} is not set, otherwise both
+         * {@link #setSurfaceControl(SurfaceControl)} and {@link #setContext(Context)}
+         * are necessary<br/>
          * <b>It may refer to an attached view, don't use static reference for any purpose.</b>
          */
         public static class Builder {
             private View mAttrView = null;
+            private Context mAttrContext = null;
             private long mAttrTimeout = DEFAULT_TIMEOUT_MS;
             private String mAttrTag = "";
+            private boolean mAttrSurfaceOnly;
+            private SurfaceControl mAttrSurfaceControl;
             private @CujType int mAttrCujType;
 
             /**
+             * Creates a builder which instruments only surface.
              * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}.
+             * @param context context
+             * @param surfaceControl surface control
+             * @return builder
              */
-            public Builder(@CujType int cuj) {
+            public static Builder withSurface(@CujType int cuj, @NonNull Context context,
+                    @NonNull SurfaceControl surfaceControl) {
+                return new Builder(cuj)
+                        .setContext(context)
+                        .setSurfaceControl(surfaceControl)
+                        .setSurfaceOnly(true);
+            }
+
+            /**
+             * Creates a builder which instruments both surface and view.
+             * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}.
+             * @param view view
+             * @return builder
+             */
+            public static Builder withView(@CujType int cuj, @NonNull View view) {
+                return new Builder(cuj).setView(view);
+            }
+
+            private Builder(@CujType int cuj) {
                 mAttrCujType = cuj;
             }
 
             /**
+             * Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false.
              * @param view an attached view
              * @return builder
              */
-            public Builder setView(@NonNull View view) {
+            private Builder setView(@NonNull View view) {
                 mAttrView = view;
                 return this;
             }
@@ -669,20 +735,56 @@
             }
 
             /**
-             * Build the {@link Configuration} instance
+             * Indicates if only instrument with surface,
+             * if true, must also setup with {@link #setContext(Context)}
+             * and {@link #setSurfaceControl(SurfaceControl)}.
+             * @param surfaceOnly true if only instrument with surface, false otherwise
+             * @return builder Surface only builder.
+             */
+            private Builder setSurfaceOnly(boolean surfaceOnly) {
+                mAttrSurfaceOnly = surfaceOnly;
+                return this;
+            }
+
+            /**
+             * Specifies a context, must set if {@link #setSurfaceOnly(boolean)} is set.
+             */
+            private Builder setContext(Context context) {
+                mAttrContext = context;
+                return this;
+            }
+
+            /**
+             * Specifies a surface control, must be set if {@link #setSurfaceOnly(boolean)} is set.
+             */
+            private Builder setSurfaceControl(SurfaceControl surfaceControl) {
+                mAttrSurfaceControl = surfaceControl;
+                return this;
+            }
+
+            /**
+             * Builds the {@link Configuration} instance
              * @return the instance of {@link Configuration}
              * @throws IllegalArgumentException if any invalid attribute is set
              */
             public Configuration build() throws IllegalArgumentException {
-                return new Configuration(mAttrCujType, mAttrView, mAttrTag, mAttrTimeout);
+                return new Configuration(
+                        mAttrCujType, mAttrView, mAttrTag, mAttrTimeout,
+                        mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl);
             }
         }
 
-        private Configuration(@CujType int cuj, View view, String tag, long timeout) {
+        private Configuration(@CujType int cuj, View view, String tag, long timeout,
+                boolean surfaceOnly, Context context, SurfaceControl surfaceControl) {
             mCujType = cuj;
             mTag = tag;
             mTimeout = timeout;
             mView = view;
+            mSurfaceOnly = surfaceOnly;
+            mContext = context != null
+                    ? context
+                    : (view != null ? view.getContext().getApplicationContext() : null);
+            mSurfaceControl = surfaceControl;
             validate();
         }
 
@@ -698,14 +800,47 @@
                 shouldThrow = true;
                 msg.append("Invalid timeout value; ");
             }
-            if (mView == null || !mView.isAttachedToWindow()) {
-                shouldThrow = true;
-                msg.append("Null view or view is not attached yet; ");
+            if (mSurfaceOnly) {
+                if (mContext == null) {
+                    shouldThrow = true;
+                    msg.append("Must pass in a context if only instrument surface; ");
+                }
+                if (mSurfaceControl == null || !mSurfaceControl.isValid()) {
+                    shouldThrow = true;
+                    msg.append("Must pass in a valid surface control if only instrument surface; ");
+                }
+            } else {
+                if (mView == null || !mView.isAttachedToWindow()) {
+                    shouldThrow = true;
+                    msg.append("Null view or unattached view while instrumenting view; ");
+                }
             }
             if (shouldThrow) {
                 throw new IllegalArgumentException(msg.toString());
             }
         }
+
+        /**
+         * @return true if only instrumenting surface, false otherwise
+         */
+        public boolean isSurfaceOnly() {
+            return mSurfaceOnly;
+        }
+
+        /**
+         * @return the surafce control which is instrumenting
+         */
+        public SurfaceControl getSurfaceControl() {
+            return mSurfaceControl;
+        }
+
+        View getView() {
+            return mView;
+        }
+
+        Context getContext() {
+            return mContext;
+        }
     }
 
     /**
@@ -715,8 +850,8 @@
         @CujType
         private final int mCujType;
         private final long mTimeStamp;
-        @FrameTracker.Reasons
-        private int mReason = FrameTracker.REASON_END_UNKNOWN;
+        @Reasons
+        private int mReason = REASON_END_UNKNOWN;
         private final boolean mShouldNotify;
         private final String mName;
 
@@ -756,15 +891,15 @@
             return mTimeStamp;
         }
 
-        public void setReason(@FrameTracker.Reasons int reason) {
+        public void setReason(@Reasons int reason) {
             mReason = reason;
         }
 
-        public int getReason() {
+        public @Reasons int getReason() {
             return mReason;
         }
 
-        /** Determine if should notify the receivers of cuj events */
+        /** Determines if should notify the receivers of cuj events */
         public boolean shouldNotify() {
             return mShouldNotify;
         }
diff --git a/core/java/com/android/internal/os/ProcLocksReader.java b/core/java/com/android/internal/os/ProcLocksReader.java
new file mode 100644
index 0000000..bd3115fc5
--- /dev/null
+++ b/core/java/com/android/internal/os/ProcLocksReader.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import com.android.internal.util.ProcFileReader;
+
+import libcore.io.IoUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Reads and parses {@code locks} files in the {@code proc} filesystem.
+ * A typical example of /proc/locks
+ *
+ * 1: POSIX  ADVISORY  READ  18403 fd:09:9070 1073741826 1073742335
+ * 2: POSIX  ADVISORY  WRITE 18292 fd:09:34062 0 EOF
+ * 2: -> POSIX  ADVISORY  WRITE 18291 fd:09:34062 0 EOF
+ * 2: -> POSIX  ADVISORY  WRITE 18293 fd:09:34062 0 EOF
+ * 3: POSIX  ADVISORY  READ  3888 fd:09:13992 128 128
+ * 4: POSIX  ADVISORY  READ  3888 fd:09:14230 1073741826 1073742335
+ */
+public class ProcLocksReader {
+    private final String mPath;
+
+    public ProcLocksReader() {
+        mPath = "/proc/locks";
+    }
+
+    public ProcLocksReader(String path) {
+        mPath = path;
+    }
+
+    /**
+     * Checks if a process corresponding to a specific pid owns any file locks.
+     * @param pid The process ID for which we want to know the existence of file locks.
+     * @return true If the process holds any file locks, false otherwise.
+     * @throws IOException if /proc/locks can't be accessed.
+     */
+    public boolean hasFileLocks(int pid) throws Exception {
+        ProcFileReader reader = null;
+        long last = -1;
+        long id; // ordinal position of the lock in the list
+        int owner; // the PID of the process that owns the lock
+
+        try {
+            reader = new ProcFileReader(new FileInputStream(mPath));
+
+            while (reader.hasMoreData()) {
+                id = reader.nextLong(true); // lock id
+                if (id == last) {
+                    reader.finishLine(); // blocked lock
+                    continue;
+                }
+
+                reader.nextIgnored(); // lock type: POSIX?
+                reader.nextIgnored(); // lock type: MANDATORY?
+                reader.nextIgnored(); // lock type: RW?
+
+                owner = reader.nextInt(); // pid
+                if (owner == pid) {
+                    return true;
+                }
+                reader.finishLine();
+                last = id;
+            }
+        } catch (IOException e) {
+            // TODO: let ProcFileReader log the failed line
+            throw new Exception("Exception parsing /proc/locks");
+        } finally {
+            IoUtils.closeQuietly(reader);
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 10224a4..353c6c0 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -28,7 +28,7 @@
  */
 public class ProtoLogImpl extends BaseProtoLogImpl {
     private static final int BUFFER_CAPACITY = 1024 * 1024;
-    private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
+    private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
     private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
 
     private static ProtoLogImpl sServiceInstance = null;
diff --git a/core/java/com/android/internal/util/ProcFileReader.java b/core/java/com/android/internal/util/ProcFileReader.java
index ead58c7d..0dd8ad8 100644
--- a/core/java/com/android/internal/util/ProcFileReader.java
+++ b/core/java/com/android/internal/util/ProcFileReader.java
@@ -28,8 +28,8 @@
  * requires each line boundary to be explicitly acknowledged using
  * {@link #finishLine()}. Assumes {@link StandardCharsets#US_ASCII} encoding.
  * <p>
- * Currently doesn't support formats based on {@code \0}, tabs, or repeated
- * delimiters.
+ * Currently doesn't support formats based on {@code \0}, tabs.
+ * Consecutive spaces are treated as a single delimiter.
  */
 public class ProcFileReader implements Closeable {
     private final InputStream mStream;
@@ -75,6 +75,11 @@
     private void consumeBuf(int count) throws IOException {
         // TODO: consider moving to read pointer, but for now traceview says
         // these copies aren't a bottleneck.
+
+        // skip all consecutive delimiters.
+        while (count < mTail && mBuffer[count] == ' ') {
+            count++;
+        }
         System.arraycopy(mBuffer, count, mBuffer, 0, mTail - count);
         mTail -= count;
         if (mTail == 0) {
@@ -159,11 +164,18 @@
      * Parse and return next token as base-10 encoded {@code long}.
      */
     public long nextLong() throws IOException {
+        return nextLong(false);
+    }
+
+    /**
+     * Parse and return next token as base-10 encoded {@code long}.
+     */
+    public long nextLong(boolean stopAtInvalid) throws IOException {
         final int tokenIndex = nextTokenIndex();
         if (tokenIndex == -1) {
             throw new ProtocolException("Missing required long");
         } else {
-            return parseAndConsumeLong(tokenIndex);
+            return parseAndConsumeLong(tokenIndex, stopAtInvalid);
         }
     }
 
@@ -176,7 +188,7 @@
         if (tokenIndex == -1) {
             return def;
         } else {
-            return parseAndConsumeLong(tokenIndex);
+            return parseAndConsumeLong(tokenIndex, false);
         }
     }
 
@@ -186,7 +198,10 @@
         return s;
     }
 
-    private long parseAndConsumeLong(int tokenIndex) throws IOException {
+    /**
+     * If stopAtInvalid is true, don't throw IOException but return whatever parsed so far.
+     */
+    private long parseAndConsumeLong(int tokenIndex, boolean stopAtInvalid) throws IOException {
         final boolean negative = mBuffer[0] == '-';
 
         // TODO: refactor into something like IntegralToString
@@ -194,7 +209,11 @@
         for (int i = negative ? 1 : 0; i < tokenIndex; i++) {
             final int digit = mBuffer[i] - '0';
             if (digit < 0 || digit > 9) {
-                throw invalidLong(tokenIndex);
+                if (stopAtInvalid) {
+                    break;
+                } else {
+                    throw invalidLong(tokenIndex);
+                }
             }
 
             // always parse as negative number and apply sign later; this
@@ -226,6 +245,18 @@
         return (int) value;
     }
 
+    /**
+     * Bypass the next token.
+     */
+    public void nextIgnored() throws IOException {
+        final int tokenIndex = nextTokenIndex();
+        if (tokenIndex == -1) {
+            throw new ProtocolException("Missing required token");
+        } else {
+            consumeBuf(tokenIndex + 1);
+        }
+    }
+
     @Override
     public void close() throws IOException {
         mStream.close();
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
deleted file mode 100644
index fdbbf97..0000000
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open 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.view;
-
-import android.annotation.AnyThread;
-import android.annotation.BinderThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Trace;
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.CompletionInfo;
-import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.DumpableInputConnection;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionInspector;
-import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
-import android.view.inputmethod.InputContentInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.SurroundingText;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.inputmethod.CallbackUtils;
-import com.android.internal.inputmethod.ImeTracing;
-import com.android.internal.inputmethod.InputConnectionCommand;
-import com.android.internal.inputmethod.InputConnectionCommandType;
-import com.android.internal.inputmethod.InputConnectionProtoDumper;
-import com.android.internal.inputmethod.InputMethodDebug;
-
-import java.lang.ref.WeakReference;
-
-public final class IInputConnectionWrapper extends IInputContext.Stub {
-    private static final String TAG = "IInputConnectionWrapper";
-    private static final boolean DEBUG = false;
-
-    private static final int DO_EDIT = 10;
-    private static final int DO_CLOSE_CONNECTION = 20;
-
-    @GuardedBy("mLock")
-    @Nullable
-    private InputConnection mInputConnection;
-
-    private Looper mMainLooper;
-    private Handler mH;
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private boolean mFinished = false;
-
-    private final InputMethodManager mParentInputMethodManager;
-    private final WeakReference<View> mServedView;
-
-    class MyHandler extends Handler {
-        MyHandler(Looper looper) {
-            super(looper);
-        }
-        
-        @Override
-        public void handleMessage(Message msg) {
-            executeMessage(msg);
-        }
-    }
-
-    public IInputConnectionWrapper(@NonNull Looper mainLooper,
-            @NonNull InputConnection inputConnection,
-            @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
-        mInputConnection = inputConnection;
-        mMainLooper = mainLooper;
-        mH = new MyHandler(mMainLooper);
-        mParentInputMethodManager = inputMethodManager;
-        mServedView = new WeakReference<>(servedView);
-    }
-
-    @Nullable
-    public InputConnection getInputConnection() {
-        synchronized (mLock) {
-            return mInputConnection;
-        }
-    }
-
-    private boolean isFinished() {
-        synchronized (mLock) {
-            return mFinished;
-        }
-    }
-
-    public boolean isActive() {
-        return mParentInputMethodManager.isActive() && !isFinished();
-    }
-
-    public View getServedView() {
-        return mServedView.get();
-    }
-
-    public void deactivate() {
-        if (isFinished()) {
-            // This is a small performance optimization.  Still only the 1st call of
-            // reportFinish() will take effect.
-            return;
-        }
-        dispatchMessage(mH.obtainMessage(DO_CLOSE_CONNECTION));
-
-        // Notify the app that the InputConnection was closed.
-        final View servedView = mServedView.get();
-        if (servedView != null) {
-            final Handler handler = servedView.getHandler();
-            // The handler is null if the view is already detached. When that's the case, for
-            // now, we simply don't dispatch this callback.
-            if (handler != null) {
-                if (DEBUG) {
-                    Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
-                }
-                if (handler.getLooper().isCurrentThread()) {
-                    servedView.onInputConnectionClosedInternal();
-                } else {
-                    handler.post(servedView::onInputConnectionClosedInternal);
-                }
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "IInputConnectionWrapper{"
-                + "connection=" + getInputConnection()
-                + " finished=" + isFinished()
-                + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive()
-                + " mServedView=" + mServedView.get()
-                + "}";
-    }
-
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        synchronized (mLock) {
-            // Check that the call is initiated in the main thread of the current InputConnection
-            // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
-            // executed on this thread. Otherwise the messages are dispatched to the correct thread
-            // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
-            // reasons.
-            if ((mInputConnection instanceof DumpableInputConnection)
-                    && Looper.myLooper() == mMainLooper) {
-                ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId);
-            }
-        }
-    }
-
-    @BinderThread
-    @Override
-    public void doEdit(@Nullable InputConnectionCommand command) {
-        if (command == null) {
-            // As long as everything is working as expected, we should never see any null object
-            // here.  If we are seeing null object, it means that either the sender or
-            // InputConnectionCommand.CREATOR#createFromParcel() returned null for whatever
-            // unexpected reasons.  Note that InputConnectionCommand.CREATOR#createFromParcel() does
-            // some data verifications.  Hence failing to pass the verification is one of the
-            // reasons to see null here.
-            Log.w(TAG, "Ignoring invalid InputConnectionCommand.");
-            return;
-        }
-        if (DEBUG) {
-            Log.d(TAG, "incoming: " + InputMethodDebug.dumpInputConnectionCommand(command));
-        }
-        dispatchMessage(mH.obtainMessage(DO_EDIT, command));
-    }
-
-    /**
-     * Exposed for {@link InputMethodManager} to trigger
-     * {@link InputConnection#finishComposingText()}.
-     */
-    @AnyThread
-    public void finishComposingText() {
-        dispatchMessage(mH.obtainMessage(DO_EDIT, InputConnectionCommand.create(
-                InputConnectionCommandType.FINISH_COMPOSING_TEXT)));
-    }
-
-    void dispatchMessage(Message msg) {
-        // If we are calling this from the main thread, then we can call
-        // right through.  Otherwise, we need to send the message to the
-        // main thread.
-        if (Looper.myLooper() == mMainLooper) {
-            executeMessage(msg);
-            msg.recycle();
-            return;
-        }
-        
-        mH.sendMessage(msg);
-    }
-
-    private void executeMessage(Message msg) {
-        switch (msg.what) {
-            case DO_EDIT:
-                doEditMain((InputConnectionCommand) msg.obj);
-                break;
-            case DO_CLOSE_CONNECTION:
-                // Note that we do not need to worry about race condition here, because 1) mFinished
-                // is updated only inside this block, and 2) the code here is running on a Handler
-                // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
-                // same time.
-                if (isFinished()) {
-                    return;
-                }
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
-                try {
-                    InputConnection ic = getInputConnection();
-                    // Note we do NOT check isActive() here, because this is safe
-                    // for an IME to call at any time, and we need to allow it
-                    // through to clean up our state after the IME has switched to
-                    // another client.
-                    if (ic == null) {
-                        return;
-                    }
-                    @MissingMethodFlags final int missingMethods =
-                            InputConnectionInspector.getMissingMethodFlags(ic);
-                    if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
-                        ic.closeConnection();
-                    }
-                } finally {
-                    synchronized (mLock) {
-                        mInputConnection = null;
-                        mFinished = true;
-                    }
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                break;
-        }
-    }
-
-    private void doEditMain(@NonNull InputConnectionCommand command) {
-        if (DEBUG) {
-            Log.d(TAG, "handling: " + InputMethodDebug.dumpInputConnectionCommand(command));
-        }
-        byte[] icProto;
-        switch (command.mCommandType) {
-            case InputConnectionCommandType.GET_TEXT_AFTER_CURSOR: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
-                try {
-                    final int n = command.mIntArg0;
-                    final int flags = command.mFlags;
-                    final InputConnection ic = getInputConnection();
-                    final CharSequence result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
-                        result = null;
-                    } else {
-                        result = ic.getTextAfterCursor(n, flags);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetTextAfterCursorProto(n, flags,
-                                result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.GET_TEXT_BEFORE_CURSOR: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
-                try {
-                    final int n = command.mIntArg0;
-                    final int flags = command.mFlags;
-                    final InputConnection ic = getInputConnection();
-                    final CharSequence result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
-                        result = null;
-                    } else {
-                        result = ic.getTextBeforeCursor(n, flags);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetTextBeforeCursorProto(n, flags,
-                                result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.GET_SELECTED_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
-                try {
-                    final int flags = command.mFlags;
-                    final InputConnection ic = getInputConnection();
-                    final CharSequence result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getSelectedText on inactive InputConnection");
-                        result = null;
-                    } else {
-                        result = ic.getSelectedText(flags);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetSelectedTextProto(flags,
-                                result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getSelectedText", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.GET_SURROUNDING_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
-                try {
-                    final int beforeLength = command.mIntArg0;
-                    final int afterLength  = command.mIntArg1;
-                    final int flags = command.mFlags;
-                    final InputConnection ic = getInputConnection();
-                    final SurroundingText result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getSurroundingText on inactive InputConnection");
-                        result = null;
-                    } else {
-                        result = ic.getSurroundingText(beforeLength, afterLength, flags);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetSurroundingTextProto(
-                                beforeLength, afterLength, flags, result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.GET_CURSOR_CAPS_MODE: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
-                try {
-                    final int reqModes = command.mIntArg0;
-                    final InputConnection ic = getInputConnection();
-                    final int result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
-                        result = 0;
-                    } else {
-                        result = ic.getCursorCapsMode(reqModes);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetCursorCapsModeProto(reqModes,
-                                result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.GET_EXTRACTED_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
-                try {
-                    final ExtractedTextRequest request = (ExtractedTextRequest) command.mParcelable;
-                    final int flags = command.mFlags;
-                    final InputConnection ic = getInputConnection();
-                    final ExtractedText result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "getExtractedText on inactive InputConnection");
-                        result = null;
-                    } else {
-                        result = ic.getExtractedText(request, flags);
-                    }
-                    if (ImeTracing.getInstance().isEnabled()) {
-                        icProto = InputConnectionProtoDumper.buildGetExtractedTextProto(request,
-                                flags, result);
-                        ImeTracing.getInstance().triggerClientDump(
-                                TAG + "#getExtractedText", mParentInputMethodManager, icProto);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.COMMIT_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
-                try {
-                    final CharSequence text = command.mCharSequence;
-                    final int newCursorPosition = command.mIntArg0;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "commitText on inactive InputConnection");
-                        return;
-                    }
-                    ic.commitText(text, newCursorPosition);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.SET_SELECTION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
-                try {
-                    final int start = command.mIntArg0;
-                    final int end = command.mIntArg1;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "setSelection on inactive InputConnection");
-                        return;
-                    }
-                    ic.setSelection(start, end);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.PERFORM_EDITOR_ACTION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
-                try {
-                    final int editorAction = command.mIntArg0;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "performEditorAction on inactive InputConnection");
-                        return;
-                    }
-                    ic.performEditorAction(editorAction);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.PERFORM_CONTEXT_MENU_ACTION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
-                try {
-                    final int id = command.mIntArg0;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "performContextMenuAction on inactive InputConnection");
-                        return;
-                    }
-                    ic.performContextMenuAction(id);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.COMMIT_COMPLETION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
-                try {
-                    final CompletionInfo text = (CompletionInfo) command.mParcelable;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "commitCompletion on inactive InputConnection");
-                        return;
-                    }
-                    ic.commitCompletion(text);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.COMMIT_CORRECTION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
-                try {
-                    final CorrectionInfo correctionInfo = (CorrectionInfo) command.mParcelable;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "commitCorrection on inactive InputConnection");
-                        return;
-                    }
-                    ic.commitCorrection(correctionInfo);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.SET_COMPOSING_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
-                try {
-                    final CharSequence text = command.mCharSequence;
-                    final int newCursorPosition = command.mIntArg0;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "setComposingText on inactive InputConnection");
-                        return;
-                    }
-                    ic.setComposingText(text, newCursorPosition);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.SET_COMPOSING_REGION: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
-                try {
-                    final int start = command.mIntArg0;
-                    final int end = command.mIntArg1;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "setComposingRegion on inactive InputConnection");
-                        return;
-                    }
-                    ic.setComposingRegion(start, end);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.FINISH_COMPOSING_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
-                try {
-                    if (isFinished()) {
-                        // In this case, #finishComposingText() is guaranteed to be called already.
-                        // There should be no negative impact if we ignore this call silently.
-                        if (DEBUG) {
-                            Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
-                        }
-                        return;
-                    }
-                    InputConnection ic = getInputConnection();
-                    // Note we do NOT check isActive() here, because this is safe
-                    // for an IME to call at any time, and we need to allow it
-                    // through to clean up our state after the IME has switched to
-                    // another client.
-                    if (ic == null) {
-                        Log.w(TAG, "finishComposingText on inactive InputConnection");
-                        return;
-                    }
-                    ic.finishComposingText();
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.SEND_KEY_EVENT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
-                try {
-                    final KeyEvent event = (KeyEvent) command.mParcelable;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "sendKeyEvent on inactive InputConnection");
-                        return;
-                    }
-                    ic.sendKeyEvent(event);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.CLEAR_META_KEY_STATES: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
-                try {
-                    final int states = command.mIntArg0;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
-                        return;
-                    }
-                    ic.clearMetaKeyStates(states);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
-                try {
-                    final int beforeLength = command.mIntArg0;
-                    final int afterLength = command.mIntArg1;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
-                        return;
-                    }
-                    ic.deleteSurroundingText(beforeLength, afterLength);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT,
-                        "InputConnection#deleteSurroundingTextInCodePoints");
-                try {
-                    final int beforeLength = command.mIntArg0;
-                    final int afterLength = command.mIntArg1;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
-                        return;
-                    }
-                    ic.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.BEGIN_BATCH_EDIT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
-                try {
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "beginBatchEdit on inactive InputConnection");
-                        return;
-                    }
-                    ic.beginBatchEdit();
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.END_BATCH_EDIT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
-                try {
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "endBatchEdit on inactive InputConnection");
-                        return;
-                    }
-                    ic.endBatchEdit();
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.PERFORM_SPELL_CHECK: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performSpellCheck");
-                try {
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "performSpellCheck on inactive InputConnection");
-                        return;
-                    }
-                    ic.performSpellCheck();
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.PERFORM_PRIVATE_COMMAND: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
-                try {
-                    final String action = command.mString;
-                    final Bundle data = command.mBundle;
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "performPrivateCommand on inactive InputConnection");
-                        return;
-                    }
-                    ic.performPrivateCommand(action, data);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.REQUEST_CURSOR_UPDATES: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
-                try {
-                    final int cursorUpdateMode = command.mIntArg0;
-                    final InputConnection ic = getInputConnection();
-                    final boolean result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
-                        result = false;
-                    } else {
-                        result = ic.requestCursorUpdates(cursorUpdateMode);
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.COMMIT_CONTENT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
-                try {
-                    final InputContentInfo inputContentInfo =
-                            (InputContentInfo) command.mParcelable;
-                    final int flags = command.mFlags;
-                    final Bundle opts = command.mBundle;
-                    final InputConnection ic = getInputConnection();
-                    final boolean result;
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG, "commitContent on inactive InputConnection");
-                        result = false;
-                    } else {
-                        if (inputContentInfo == null || !inputContentInfo.validate()) {
-                            Log.w(TAG, "commitContent with invalid inputContentInfo="
-                                    + inputContentInfo);
-                            result = false;
-                        } else {
-                            result = ic.commitContent(inputContentInfo, flags, opts);
-                        }
-                    }
-                    CallbackUtils.onResult(command, result, TAG);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-            case InputConnectionCommandType.SET_IME_CONSUMES_INPUT: {
-                Trace.traceBegin(Trace.TRACE_TAG_INPUT,
-                        "InputConnection#setImeConsumesInput");
-                try {
-                    final boolean imeConsumesInput = (command.mIntArg0 != 0);
-                    InputConnection ic = getInputConnection();
-                    if (ic == null || !isActive()) {
-                        Log.w(TAG,
-                                "setImeConsumesInput on inactive InputConnection");
-                        return;
-                    }
-                    ic.setImeConsumesInput(imeConsumesInput);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_INPUT);
-                }
-                return;
-            }
-        }
-    }
-}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 095c0b4..dd42c40e 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -16,13 +16,76 @@
 
 package com.android.internal.view;
 
-import com.android.internal.inputmethod.InputConnectionCommand;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputContentInfo;
+
+import com.android.internal.inputmethod.IBooleanResultCallback;
+import com.android.internal.inputmethod.ICharSequenceResultCallback;
+import com.android.internal.inputmethod.IExtractedTextResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
+import com.android.internal.inputmethod.ISurroundingTextResultCallback;
 
 /**
  * Interface from an input method to the application, allowing it to perform
  * edits on the current input field and other interactions with the application.
  * {@hide}
  */
-oneway interface IInputContext {
-    void doEdit(in InputConnectionCommand command);
+ oneway interface IInputContext {
+    void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
+
+    void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
+
+    void getCursorCapsMode(int reqModes, IIntResultCallback callback);
+
+    void getExtractedText(in ExtractedTextRequest request, int flags,
+            IExtractedTextResultCallback callback);
+
+    void deleteSurroundingText(int beforeLength, int afterLength);
+    void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
+
+    void setComposingText(CharSequence text, int newCursorPosition);
+
+    void finishComposingText();
+    
+    void commitText(CharSequence text, int newCursorPosition);
+
+    void commitCompletion(in CompletionInfo completion);
+
+    void commitCorrection(in CorrectionInfo correction);
+
+    void setSelection(int start, int end);
+    
+    void performEditorAction(int actionCode);
+    
+    void performContextMenuAction(int id);
+    
+    void beginBatchEdit();
+    
+    void endBatchEdit();
+
+    void sendKeyEvent(in KeyEvent event);
+    
+    void clearMetaKeyStates(int states);
+    
+    void performSpellCheck();
+
+    void performPrivateCommand(String action, in Bundle data);
+
+    void setComposingRegion(int start, int end);
+
+    void getSelectedText(int flags, ICharSequenceResultCallback callback);
+
+    void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
+
+    void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
+            IBooleanResultCallback callback);
+
+    void getSurroundingText(int beforeLength, int afterLength, int flags,
+            ISurroundingTextResultCallback callback);
+
+    void setImeConsumesInput(boolean imeConsumesInput);
 }
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index f5c2a2a..e72afdd 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -16,7 +16,7 @@
 
 package com.android.internal.view;
 
-import com.android.internal.view.InputBindResult;
+import com.android.internal.inputmethod.InputBindResult;
 
 /**
  * Interface a client of the IInputMethodManager implements, to identify
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index d40c064..4b72355 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -21,7 +21,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.EditorInfo;
 
-import com.android.internal.view.InputBindResult;
+import com.android.internal.inputmethod.InputBindResult;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 0c2d2a9..3191e23 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -53,6 +53,8 @@
     private int mEmphasizedHeight;
     private int mRegularHeight;
     @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
+    int mNumNotGoneChildren;
+    int mNumPriorityChildren;
 
     public NotificationActionListLayout(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -76,15 +78,14 @@
                 && ((EmphasizedNotificationButton) actionView).isPriority();
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int N = getChildCount();
+    private void countAndRebuildMeasureOrder() {
+        final int numChildren = getChildCount();
         int textViews = 0;
         int otherViews = 0;
-        int notGoneChildren = 0;
-        int priorityChildren = 0;
+        mNumNotGoneChildren = 0;
+        mNumPriorityChildren = 0;
 
-        for (int i = 0; i < N; i++) {
+        for (int i = 0; i < numChildren; i++) {
             View c = getChildAt(i);
             if (c instanceof TextView) {
                 textViews++;
@@ -92,9 +93,9 @@
                 otherViews++;
             }
             if (c.getVisibility() != GONE) {
-                notGoneChildren++;
+                mNumNotGoneChildren++;
                 if (isPriority(c)) {
-                    priorityChildren++;
+                    mNumPriorityChildren++;
                 }
             }
         }
@@ -119,17 +120,20 @@
         if (needRebuild) {
             rebuildMeasureOrder(textViews, otherViews);
         }
+    }
 
+    private int measureAndGetUsedWidth(int widthMeasureSpec, int heightMeasureSpec, int innerWidth,
+            boolean collapsePriorityActions) {
+        final int numChildren = getChildCount();
         final boolean constrained =
                 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
-
-        final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
         final int otherSize = mMeasureOrderOther.size();
         int usedWidth = 0;
 
+        int maxPriorityWidth = 0;
         int measuredChildren = 0;
         int measuredPriorityChildren = 0;
-        for (int i = 0; i < N; i++) {
+        for (int i = 0; i < numChildren; i++) {
             // Measure shortest children first. To avoid measuring twice, we approximate by looking
             // at the text length.
             final boolean isPriority;
@@ -154,12 +158,20 @@
                 // measure in the order of (approx.) size, a large view can still take more than its
                 // share if the others are small.
                 int availableWidth = innerWidth - usedWidth;
-                int unmeasuredChildren = notGoneChildren - measuredChildren;
+                int unmeasuredChildren = mNumNotGoneChildren - measuredChildren;
                 int maxWidthForChild = availableWidth / unmeasuredChildren;
-                if (isPriority) {
+                if (isPriority && collapsePriorityActions) {
+                    // Collapsing the actions to just the width required to show the icon.
+                    if (maxPriorityWidth == 0) {
+                        maxPriorityWidth = getResources().getDimensionPixelSize(
+                                R.dimen.notification_actions_collapsed_priority_width);
+                    }
+                    maxWidthForChild = maxPriorityWidth + lp.leftMargin + lp.rightMargin;
+                } else if (isPriority) {
                     // Priority children get a larger maximum share of the total space:
                     //  maximum priority share = (nPriority + 1) / (MAX + 1)
-                    int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren;
+                    int unmeasuredPriorityChildren = mNumPriorityChildren
+                            - measuredPriorityChildren;
                     int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
                     int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
                             / (Notification.MAX_ACTION_BUTTONS + 1);
@@ -187,6 +199,19 @@
         } else {
             mExtraStartPadding = 0;
         }
+        return usedWidth;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        countAndRebuildMeasureOrder();
+        final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
+        int usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
+                false /* collapsePriorityButtons */);
+        if (mNumPriorityChildren != 0 && usedWidth >= innerWidth) {
+            usedWidth = measureAndGetUsedWidth(widthMeasureSpec, heightMeasureSpec, innerWidth,
+                    true /* collapsePriorityButtons */);
+        }
 
         mTotalWidth = usedWidth + mPaddingRight + mPaddingLeft + mExtraStartPadding;
         setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index b46b5a2..d4ae6d7 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -105,9 +105,11 @@
 }
 
 static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
-                         jlong height, jint format) {
+                         jlong height, jint format, jlong transactionPtr) {
     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
-    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
+    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format,
+                  transaction);
 }
 
 static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -144,7 +146,7 @@
         {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
         {"nativeDestroy", "(J)V", (void*)nativeDestroy},
         {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
-        {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
+        {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate},
         {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue},
         {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
         {"nativeSetTransactionCompleteCallback",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a6d038d..8a1f1a0 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2432,6 +2432,12 @@
     return (jint)nativeToJavaStatus(status);
 }
 
+static jint android_media_AudioSystem_setHotwordDetectionServiceUid(JNIEnv *env, jobject thiz,
+                                                                    jint uid) {
+    status_t status = AudioSystem::setHotwordDetectionServiceUid(uid);
+    return (jint)nativeToJavaStatus(status);
+}
+
 static jint
 android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArray uids) {
     std::vector<uid_t> nativeUidsVector;
@@ -2804,6 +2810,8 @@
          {"setSurroundFormatEnabled", "(IZ)I",
           (void *)android_media_AudioSystem_setSurroundFormatEnabled},
          {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
+         {"setHotwordDetectionServiceUid", "(I)I",
+          (void *)android_media_AudioSystem_setHotwordDetectionServiceUid},
          {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
          {"isHapticPlaybackSupported", "()Z",
           (void *)android_media_AudioSystem_isHapticPlaybackSupported},
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index a699f91..7b79b38 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -54,6 +54,7 @@
     jmethodID onPointerCaptureEvent;
     jmethodID onDragEvent;
     jmethodID onBatchedInputEventPending;
+    jmethodID onTouchModeChanged;
 } gInputEventReceiverClassInfo;
 
 // Add prefix to the beginning of each line in 'str'
@@ -424,6 +425,18 @@
                 finishInputEvent(seq, true /* handled */);
                 continue;
             }
+            case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+                const TouchModeEvent* touchModeEvent = static_cast<TouchModeEvent*>(inputEvent);
+                if (kDebugDispatchCycle) {
+                    ALOGD("channel '%s' ~ Received touch mode event: isInTouchMode=%s",
+                          getInputChannelName().c_str(), toString(touchModeEvent->isInTouchMode()));
+                }
+                env->CallVoidMethod(receiverObj.get(),
+                                    gInputEventReceiverClassInfo.onTouchModeChanged,
+                                    jboolean(touchModeEvent->isInTouchMode()));
+                finishInputEvent(seq, true /* handled */);
+                continue;
+            }
 
             default:
                 assert(false); // InputConsumer should prevent this from ever happening
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3f2752d..f924229 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -552,6 +552,8 @@
     <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
     <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
     <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
+    <protected-broadcast android:name="com.android.settings.network.DELETE_SUBSCRIPTION" />
+    <protected-broadcast android:name="com.android.settings.network.SWITCH_TO_SUBSCRIPTION" />
     <protected-broadcast android:name="com.android.settings.wifi.action.NETWORK_REQUEST" />
 
     <protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
@@ -3468,6 +3470,13 @@
     <permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to trigger profcollect report upload via shell.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
+    <permission android:name="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
         @hide
         @SystemApi -->
@@ -3509,7 +3518,7 @@
          use by third party apps.
          @hide -->
     <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
-        android:protectionLevel="signature|privileged|installer" />
+        android:protectionLevel="signature|privileged|installer|role" />
 
     <!-- @SystemApi Allows an application to update the user app op restrictions.
          Not for use by third party apps.
diff --git a/core/res/res/drawable-watch/global_action_icon_background.xml b/core/res/res/drawable-watch/global_action_icon_background.xml
deleted file mode 100644
index b7bc7e6..0000000
--- a/core/res/res/drawable-watch/global_action_icon_background.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-        android:shape="oval"
-        android:tint="?android:attr/colorButtonNormal">
-    <solid android:color="@android:color/white"/>
-    <size android:height="40dp" android:width="40dp"/>
-</shape>
diff --git a/core/res/res/drawable-watch/global_action_item_divider.xml b/core/res/res/drawable-watch/global_action_item_divider.xml
new file mode 100644
index 0000000..89f3ef4
--- /dev/null
+++ b/core/res/res/drawable-watch/global_action_item_divider.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@android:color/transparent" />
+    <size android:height="4dp" />
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/global_actions_item_grey_background.xml b/core/res/res/drawable-watch/global_actions_item_grey_background.xml
new file mode 100644
index 0000000..2cff81d
--- /dev/null
+++ b/core/res/res/drawable-watch/global_actions_item_grey_background.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorControlHighlight">
+    <item android:drawable="@drawable/global_actions_item_grey_background_shape"/>
+</ripple>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/global_actions_item_grey_background_shape.xml b/core/res/res/drawable-watch/global_actions_item_grey_background_shape.xml
new file mode 100644
index 0000000..f2df319
--- /dev/null
+++ b/core/res/res/drawable-watch/global_actions_item_grey_background_shape.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:radius="26dp"/>
+    <solid android:color="@color/wear_material_grey_900"/>
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/global_actions_item_red_background.xml b/core/res/res/drawable-watch/global_actions_item_red_background.xml
new file mode 100644
index 0000000..4be8f2d
--- /dev/null
+++ b/core/res/res/drawable-watch/global_actions_item_red_background.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorControlHighlight">
+    <item android:drawable="@drawable/global_actions_item_red_background_shape"/>
+</ripple>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml b/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml
new file mode 100644
index 0000000..b556a1b
--- /dev/null
+++ b/core/res/res/drawable-watch/global_actions_item_red_background_shape.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:radius="26dp"/>
+    <solid android:color="@color/wear_material_red_400"/>
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/ic_lock_bugreport.xml b/core/res/res/drawable-watch/ic_lock_bugreport.xml
new file mode 100644
index 0000000..66dd392
--- /dev/null
+++ b/core/res/res/drawable-watch/ic_lock_bugreport.xml
@@ -0,0 +1,31 @@
+<!--
+    Copyright (C) 2017 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="@android:color/white">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,10V8h-2.81c-0.45,-0.78 -1.07,-1.46 -1.82,-1.96L17,4.41L15.59,3l-2.17,2.17c-0.03,-0.01 -0.05,-0.01 -0.08,-0.01c-0.16,-0.04 -0.32,-0.06 -0.49,-0.09c-0.06,-0.01 -0.11,-0.02 -0.17,-0.03C12.46,5.02 12.23,5 12,5h0c-0.49,0 -0.97,0.07 -1.42,0.18l0.02,-0.01L8.41,3L7,4.41l1.62,1.63l0.01,0C7.88,6.54 7.26,7.22 6.81,8H4v2h2.09C6.03,10.33 6,10.66 6,11v1H4v2h2v1c0,0.34 0.04,0.67 0.09,1H4v2h2.81c1.04,1.79 2.97,3 5.19,3h0c2.22,0 4.15,-1.21 5.19,-3H20v-2h-2.09l0,0c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1l0,0H20zM16,15c0,2.21 -1.79,4 -4,4c-2.21,0 -4,-1.79 -4,-4v-4c0,-2.21 1.79,-4 4,-4h0c2.21,0 4,1.79 4,4V15z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M10,14h4v2h-4z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M10,10h4v2h-4z"/>
+</vector>
diff --git a/core/res/res/drawable-watch/ic_lock_power_off.xml b/core/res/res/drawable-watch/ic_lock_power_off.xml
new file mode 100644
index 0000000..34bc88c
--- /dev/null
+++ b/core/res/res/drawable-watch/ic_lock_power_off.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="@android:color/white">
+    <path
+        android:fillColor="@android:color/black"
+        android:pathData="M11,2h2v10h-2zM18.37,5.64l-1.41,1.41c2.73,2.73 2.72,7.16 -0.01,9.89 -2.73,2.73 -7.17,2.73 -9.89,0.01 -2.73,-2.73 -2.74,-7.18 -0.01,-9.91l-1.41,-1.4c-3.51,3.51 -3.51,9.21 0.01,12.73 3.51,3.51 9.21,3.51 12.72,-0.01 3.51,-3.51 3.51,-9.2 0,-12.72z"/>
+</vector>
diff --git a/core/res/res/drawable-watch/ic_restart.xml b/core/res/res/drawable-watch/ic_restart.xml
new file mode 100644
index 0000000..24d7c34
--- /dev/null
+++ b/core/res/res/drawable-watch/ic_restart.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="@android:color/white">
+    <path
+        android:fillColor="@android:color/black"
+        android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02c-2.83,-0.48 -5,-2.94 -5,-5.91zM20,13c0,-4.42 -3.58,-8 -8,-8 -0.06,0 -0.12,0.01 -0.18,0.01l1.09,-1.09L11.5,2.5 8,6l3.5,3.5 1.41,-1.41 -1.08,-1.08c0.06,0 0.12,-0.01 0.17,-0.01 3.31,0 6,2.69 6,6 0,2.97 -2.17,5.43 -5,5.91v2.02c3.95,-0.49 7,-3.85 7,-7.93z"/>
+</vector>
diff --git a/core/res/res/drawable/btn_notification_emphasized.xml b/core/res/res/drawable/btn_notification_emphasized.xml
index 29c51f2a..7c09fb8 100644
--- a/core/res/res/drawable/btn_notification_emphasized.xml
+++ b/core/res/res/drawable/btn_notification_emphasized.xml
@@ -24,9 +24,9 @@
             android:insetBottom="@dimen/button_inset_vertical_material">
             <shape android:shape="rectangle">
                 <corners android:radius="@dimen/notification_action_button_radius" />
-                <padding android:left="12dp"
+                <padding android:left="16dp"
                          android:top="@dimen/button_padding_vertical_material"
-                         android:right="12dp"
+                         android:right="16dp"
                          android:bottom="@dimen/button_padding_vertical_material" />
                 <solid android:color="@color/white" />
             </shape>
diff --git a/core/res/res/layout-watch/global_actions.xml b/core/res/res/layout-watch/global_actions.xml
index c50d3f7..b7479d8 100644
--- a/core/res/res/layout-watch/global_actions.xml
+++ b/core/res/res/layout-watch/global_actions.xml
@@ -16,7 +16,6 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center_vertical"
-        android:paddingTop="?attr/dialogPreferredPadding"
-        android:paddingBottom="?attr/dialogPreferredPadding"
+        android:showDividers="middle"
+        android:divider="@drawable/global_action_item_divider"
         android:orientation="vertical"/>
diff --git a/core/res/res/layout-watch/global_actions_item.xml b/core/res/res/layout-watch/global_actions_item.xml
index ae87e63c..3d3f341 100644
--- a/core/res/res/layout-watch/global_actions_item.xml
+++ b/core/res/res/layout-watch/global_actions_item.xml
@@ -13,52 +13,35 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:gravity="center"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-    <LinearLayout
+	android:layout_height="wrap_content"
+        android:gravity="center"
+        android:minHeight="52dp"
+        android:minWidth="172dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:paddingTop="6dp"
+        android:paddingBottom="6dp"
+        android:background="@drawable/global_actions_item_grey_background">
+
+    <ImageView android:id="@+id/icon"
             android:duplicateParentState="true"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:maxHeight="?attr/listPreferredItemHeightSmall"
-            android:gravity="center_vertical"
-            android:paddingStart="?attr/listPreferredItemPaddingStart"
-            android:paddingEnd="?attr/listPreferredItemPaddingEnd"
-            android:background="?attr/selectableItemBackground"
-            android:clipToPadding="false">
+            android:scaleType="centerInside"
+            android:gravity="center"
+            android:layout_marginEnd="8dp"
+            android:layout_width="24dp"
+            android:layout_height="24dp"/>
 
-        <ImageView android:id="@+id/icon"
-                android:duplicateParentState="true"
-                android:background="@drawable/global_action_icon_background"
-                android:scaleType="centerInside"
-                android:padding="8dp"
-                android:gravity="center"
-                android:layout_marginEnd="8dp"
-                android:layout_marginTop="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_width="40dp"
-                android:layout_height="40dp"/>
-
-        <FrameLayout android:id="@+id/widget_frame"
-                android:duplicateParentState="true"
-                android:gravity="center"
-                android:visibility="gone"
-                android:orientation="horizontal"
-                android:layout_marginEnd="8dp"
-                android:layout_marginTop="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_width="40dp"
-                android:layout_height="40dp"/>
-
-        <TextView android:id="@+id/message"
-                android:duplicateParentState="true"
-                android:textAppearance="?attr/textAppearanceListItem"
-                android:ellipsize="end"
-                android:layout_weight="1"
-                android:layout_marginTop="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"/>
-    </LinearLayout>
-</FrameLayout>
+    <TextView android:id="@+id/message"
+            android:duplicateParentState="true"
+            android:ellipsize="end"
+            android:textSize="15sp"
+            android:letterSpacing="0.013"
+            android:fadingEdgeLength="12dp"
+            android:textColor="@android:color/white"
+            android:layout_weight="1"
+            android:fontFamily="google-sans-text-medium"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index aa050f3..2b9f952 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -26,6 +26,7 @@
           android:layout_width="wrap_content"
           android:layout_gravity="center"
           android:padding="0dp"
+          android:background="@null"
           android:contentDescription="@string/splash_screen_view_icon_description"/>
 
     <View android:id="@+id/splashscreen_branding_view"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7bcd93e..7e3f16b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2080,7 +2080,7 @@
     <string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع الاتصال"</string>
     <string name="call_notification_incoming_text" msgid="6143109825406638201">"مكالمة واردة"</string>
     <string name="call_notification_ongoing_text" msgid="3880832933933020875">"مكالمة جارية"</string>
-    <string name="call_notification_screening_text" msgid="8396931408268940208">"رصد مكالمة واردة"</string>
+    <string name="call_notification_screening_text" msgid="8396931408268940208">"يتم فحص المكالمة الواردة"</string>
     <plurals name="selected_count" formatted="false" msgid="3946212171128200491">
       <item quantity="zero">تم اختيار <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر</item>
       <item quantity="two">تم اختيار عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)</item>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ecb8070..4b1c544 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -984,7 +984,7 @@
     <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchtest du diese Seite wirklich verlassen?"</string>
     <string name="save_password_label" msgid="9161712335355510035">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="7065519579174882778">"Tipp: Zum Vergrößern und Verkleinern doppeltippen"</string>
-    <string name="autofill_this_form" msgid="3187132440451621492">"AutoFill"</string>
+    <string name="autofill_this_form" msgid="3187132440451621492">"Automatisches Ausfüllen"</string>
     <string name="setup_autofill" msgid="5431369130866618567">"Autom.Ausfüll.konf."</string>
     <string name="autofill_window_title" msgid="4379134104008111961">"Mit <xliff:g id="SERVICENAME">%1$s</xliff:g> automatisch ausfüllen"</string>
     <string name="autofill_address_name_separator" msgid="8190155636149596125">" "</string>
@@ -1938,7 +1938,7 @@
     <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing-Warnung"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeitsprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Gewarnt"</string>
-    <string name="notification_verified_content_description" msgid="6401483602782359391">"Bestätigt"</string>
+    <string name="notification_verified_content_description" msgid="6401483602782359391">"Verifiziert"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Maximieren"</string>
     <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Minimieren"</string>
     <string name="expand_action_accessibility" msgid="1947657036871746627">"Maximierung ein-/auschalten"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e0deab1..716b2c8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -271,7 +271,7 @@
     <string name="global_action_settings" msgid="4671878836947494217">"Ajustes"</string>
     <string name="global_action_assist" msgid="2517047220311505805">"Asistencia"</string>
     <string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
-    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo seguro"</string>
+    <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo de seguridad"</string>
     <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"&gt; 999"</string>
     <string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1c49d95..b0bc2c2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1950,7 +1950,7 @@
     <string name="maximize_button_text" msgid="4258922519914732645">"بزرگ کردن"</string>
     <string name="close_button_text" msgid="10603510034455258">"بستن"</string>
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:‏ <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
-    <string name="call_notification_answer_action" msgid="5999246836247132937">"پاسخ"</string>
+    <string name="call_notification_answer_action" msgid="5999246836247132937">"پاسخ دادن"</string>
     <string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویدیو"</string>
     <string name="call_notification_decline_action" msgid="3700345945214000726">"رد کردن"</string>
     <string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع تماس"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 07e4ffc..2d8b565 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1952,7 +1952,7 @@
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
     <string name="call_notification_answer_action" msgid="5999246836247132937">"जवाफ दिनुहोस्"</string>
     <string name="call_notification_answer_video_action" msgid="2086030940195382249">"भिडियो"</string>
-    <string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार गर्नुहोस्"</string>
+    <string name="call_notification_decline_action" msgid="3700345945214000726">"काट्नुहोस्"</string>
     <string name="call_notification_hang_up_action" msgid="9130720590159188131">"फोन राख्नुहोस्"</string>
     <string name="call_notification_incoming_text" msgid="6143109825406638201">"आगमन कल"</string>
     <string name="call_notification_ongoing_text" msgid="3880832933933020875">"भइरहेको कल"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 816ddd4..2e4578c 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -29,5 +29,8 @@
     <color name="resolver_empty_state_text">#FFFFFF</color>
     <color name="resolver_empty_state_icon">#FFFFFF</color>
 
+    <color name="call_notification_decline_color">#E66A5E</color>
+    <color name="call_notification_answer_color">#5DBA80</color>
+
     <color name="personal_apps_suspension_notification_color">#8AB4F8</color>
 </resources>
diff --git a/core/res/res/values-notround-watch/dimens.xml b/core/res/res/values-notround-watch/dimens.xml
index f0204d0..b63f9c7 100644
--- a/core/res/res/values-notround-watch/dimens.xml
+++ b/core/res/res/values-notround-watch/dimens.xml
@@ -25,4 +25,7 @@
     <item name="input_extract_action_button_width" type="dimen">24dp</item>
     <item name="input_extract_action_button_height" type="dimen">24dp</item>
     <item name="input_extract_action_icon_padding" type="dimen">3dp</item>
+
+    <item name="global_actions_vertical_padding_percentage" type="fraction">16.7%</item>
+    <item name="global_actions_horizontal_padding_percentage" type="fraction">2.8%</item>
 </resources>
diff --git a/core/res/res/values-round-watch/dimens.xml b/core/res/res/values-round-watch/dimens.xml
index 1d8c669..f288b41 100644
--- a/core/res/res/values-round-watch/dimens.xml
+++ b/core/res/res/values-round-watch/dimens.xml
@@ -25,4 +25,7 @@
     <item name="input_extract_action_button_width" type="dimen">32dp</item>
     <item name="input_extract_action_button_height" type="dimen">32dp</item>
     <item name="input_extract_action_icon_padding" type="dimen">5dp</item>
+
+    <item name="global_actions_vertical_padding_percentage" type="fraction">20.8%</item>
+    <item name="global_actions_horizontal_padding_percentage" type="fraction">5.2%</item>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9a4d41b..b19d9f4 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -68,7 +68,7 @@
     <string name="CnipMmi" msgid="4897531155968151160">"కాలింగ్ నంబర్ అందుబాటులో ఉంది"</string>
     <string name="CnirMmi" msgid="885292039284503036">"కాలింగ్ నంబర్ పరిమితం చేయబడింది"</string>
     <string name="ThreeWCMmi" msgid="2436550866139999411">"మూడు మార్గాల కాలింగ్"</string>
-    <string name="RuacMmi" msgid="1876047385848991110">"అవాంఛిత అంతరాయ కాల్‌ల తిరస్కరణ"</string>
+    <string name="RuacMmi" msgid="1876047385848991110">"అవాంఛిత అంతరాయ కాల్స్‌ల తిరస్కరణ"</string>
     <string name="CndMmi" msgid="185136449405618437">"కాలింగ్ నంబర్ బట్వాడా"</string>
     <string name="DndMmi" msgid="8797375819689129800">"అంతరాయం కలిగించవద్దు"</string>
     <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"కాలర్ ID డిఫాల్ట్‌గా పరిమితానికి ఉంటుంది. తర్వాత కాల్: పరిమితం చేయబడింది"</string>
@@ -86,8 +86,8 @@
     <string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేదు"</string>
     <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్‌వర్క్‌ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
     <string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
-    <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్‌లు చేయలేరు"</string>
-    <string name="notification_channel_network_alert" msgid="4788053066033851841">"హెచ్చరికలు"</string>
+    <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్స్‌ చేయలేరు"</string>
+    <string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్‌లు"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్‌బ్యాక్ మోడ్"</string>
     <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్థితి"</string>
@@ -124,7 +124,7 @@
     <string name="roamingTextSearching" msgid="5323235489657753486">"సేవ కోసం శోధిస్తోంది"</string>
     <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Wi‑Fi కాలింగ్‌ని సెటప్ చేయడం సాధ్యపడలేదు"</string>
   <string-array name="wfcOperatorErrorAlertMessages">
-    <item msgid="468830943567116703">"Wi-Fiతో కాల్‌లను చేయడానికి మరియు సందేశాలను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+    <item msgid="468830943567116703">"Wi-Fiతో కాల్స్‌ను చేయడానికి మరియు సందేశాలను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
     <item msgid="4795145070505729156">"మీ క్యారియర్‌తో Wi‑Fi కాలింగ్‌ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -176,10 +176,10 @@
     <string name="contentServiceSync" msgid="2341041749565687871">"సమకాలీకరణ"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"సమకాలీకరించడం సాధ్యపడదు"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"చాలా ఎక్కువ <xliff:g id="CONTENT_TYPE">%s</xliff:g> తొలగించడానికి ప్రయత్నించారు."</string>
-    <string name="low_memory" product="tablet" msgid="5557552311566179924">"టాబ్లెట్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
-    <string name="low_memory" product="watch" msgid="3479447988234030194">"వాచ్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
+    <string name="low_memory" product="tablet" msgid="5557552311566179924">"టాబ్లెట్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
+    <string name="low_memory" product="watch" msgid="3479447988234030194">"వాచ్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV పరికరం నిల్వ నిండింది. కొంత ప్రదేశాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌‌‌లను తొలగించండి."</string>
-    <string name="low_memory" product="default" msgid="2539532364144025569">"ఫోన్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
+    <string name="low_memory" product="default" msgid="2539532364144025569">"ఫోన్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
     <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
       <item quantity="other">ప్రమాణపత్ర అధికారాలు ఇన్‌స్టాల్ చేయబడ్డాయి</item>
       <item quantity="one">ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది</item>
@@ -287,7 +287,7 @@
     <string name="notification_channel_network_available" msgid="6083697929214165169">"నెట్‌వర్క్ అందుబాటులో ఉంది"</string>
     <string name="notification_channel_vpn" msgid="1628529026203808999">"VPN స్థితి"</string>
     <string name="notification_channel_device_admin" msgid="6384932669406095506">"మీ IT నిర్వాహకుల నుండి వచ్చే హెచ్చరికలు"</string>
-    <string name="notification_channel_alerts" msgid="5070241039583668427">"హెచ్చరికలు"</string>
+    <string name="notification_channel_alerts" msgid="5070241039583668427">"అలర్ట్‌లు"</string>
     <string name="notification_channel_retail_mode" msgid="3732239154256431213">"రిటైల్ డెమో"</string>
     <string name="notification_channel_usb" msgid="1528280969406244896">"USB కనెక్షన్"</string>
     <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"యాప్ అమలవుతోంది"</string>
@@ -311,7 +311,7 @@
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
     <string name="permgrouplab_storage" msgid="1938416135375282333">"ఫైల్స్, మీడియా"</string>
-    <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్‌లను యాక్సెస్ చేయడానికి"</string>
+    <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైళ్లను యాక్సెస్ చేయడానికి"</string>
     <string name="permgrouplab_microphone" msgid="2480597427667420076">"మైక్రోఫోన్"</string>
     <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ఆడియోను రికార్డ్ చేయడానికి"</string>
     <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"ఫిజికల్ యాక్టివిటీ"</string>
@@ -323,7 +323,7 @@
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"కాల్ లాగ్‌లు"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"ఫోన్ కాల్ లాగ్‌ని చదవండి మరియు రాయండి"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"ఫోన్"</string>
-    <string name="permgroupdesc_phone" msgid="270048070781478204">"ఫోన్ కాల్‌లు చేయడం మరియు నిర్వహించడం"</string>
+    <string name="permgroupdesc_phone" msgid="270048070781478204">"ఫోన్ కాల్స్‌ చేయడం మరియు నిర్వహించడం"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"శరీర సెన్సార్‌లు"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేస్తుంది"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"విండో కంటెంట్‍ను తిరిగి పొందుతుంది"</string>
@@ -352,10 +352,10 @@
     <string name="permdesc_install_shortcut" msgid="4476328467240212503">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్‌స్క్రీన్ సత్వరమార్గాలను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_uninstall_shortcut" msgid="295263654781900390">"సత్వరమార్గాలను అన్ఇన్‌స్టాల్ చేయడం"</string>
     <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్‌స్క్రీన్ సత్వరమార్గాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"అవుట్‌గోయింగ్ కాల్‌లను దారి మళ్లించడం"</string>
+    <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"అవుట్‌గోయింగ్ కాల్స్‌ను దారి మళ్లించడం"</string>
     <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్‌ను వేరే నంబర్‌కు దారి మళ్లించే లేదా మొత్తంగా కాల్‌ను ఆపివేసే ఎంపిక సహాయంతో అవుట్‌గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్‌ను చూడటానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్‌లకు సమాధానమివ్వు"</string>
-    <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్‌కమింగ్ ఫోన్ కాల్‌లకు సమాధానమివ్వడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్స్‌కు సమాధానమివ్వు"</string>
+    <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్‌కమింగ్ ఫోన్ కాల్స్‌కు సమాధానమివ్వడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_receiveSms" msgid="505961632050451881">"వచన సందేశాలను (SMS) స్వీకరించడం"</string>
     <string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
     <string name="permlab_receiveMms" msgid="4000650116674380275">"వచన సందేశాలను (MMS) స్వీకరించడం"</string>
@@ -376,15 +376,15 @@
     <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్‌ మీ ఫోన్‌లో నిల్వ చేసిన అన్ని SMS (వచన) సందేశాలను చదవగలదు."</string>
     <string name="permlab_receiveWapPush" msgid="4223747702856929056">"వచన సందేశాలను (WAP) స్వీకరించడం"</string>
     <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి మీకు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string>
-    <string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న అనువర్తనాలను పునరుద్ధరించడం"</string>
+    <string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న యాప్‌లను పునరుద్ధరించడం"</string>
     <string name="permdesc_getTasks" msgid="7388138607018233726">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి యాప్‌ను అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన యాప్‌ల గురించి సమాచారాన్ని కనుగొనడానికి యాప్‌ను అనుమతించవచ్చు."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"ప్రొఫైల్ మరియు పరికర యజమానులను నిర్వహించడం"</string>
-    <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"ప్రొఫైల్ యజమానులను మరియు పరికరం యజమానిని సెట్ చేయడానికి అనువర్తనాలను అనుమతిస్తుంది."</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"ప్రొఫైల్ యజమానులను మరియు పరికరం యజమానిని సెట్ చేయడానికి యాప్‌లను అనుమతిస్తుంది."</string>
     <string name="permlab_reorderTasks" msgid="7598562301992923804">"అమలవుతోన్న యాప్‌లను మళ్లీ క్రమం చేయడం"</string>
     <string name="permdesc_reorderTasks" msgid="8796089937352344183">"విధులను ముందుకు మరియు నేపథ్యానికి తరలించడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ ప్రమేయం లేకుండానే దీన్ని చేయవచ్చు."</string>
     <string name="permlab_enableCarMode" msgid="893019409519325311">"కారు మోడ్‌ను ప్రారంభించడం"</string>
     <string name="permdesc_enableCarMode" msgid="56419168820473508">"కారు మోడ్‌ను ప్రారంభించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"ఇతర అనువర్తనాలను మూసివేయడం"</string>
+    <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"ఇతర యాప్‌లను మూసివేయడం"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"ఇతర యాప్‌ల నేపథ్య ప్రాసెస్‌లను ముగించడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఇతర యాప్‌లు అమలు కాకుండా ఆపివేయబడవచ్చు."</string>
     <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"ఈ యాప్ ఇతర యాప్‌ల పైభాగాన కనిపించగలదు"</string>
     <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"ఈ యాప్ ఇతర యాప్‌ల పైభాగాన లేదా స్క్రీన్ యొక్క ఇతర భాగాలపైన కనిపించగలదు. ఇది సాధారణ యాప్ వినియోగానికి అంతరాయం కలిగించవచ్చు మరియు ఆ ఇతర యాప్‌లు కనిపించే విధానాన్ని మార్చవచ్చు."</string>
@@ -421,9 +421,9 @@
     <string name="permlab_readCallLog" msgid="1739990210293505948">"కాల్ లాగ్‌ను చదవడం"</string>
     <string name="permdesc_readCallLog" msgid="8964770895425873433">"ఈ యాప్‌ మీ కాల్ చరిత్రను చదవగలదు."</string>
     <string name="permlab_writeCallLog" msgid="670292975137658895">"కాల్ లాగ్‌ను వ్రాయడం"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ టాబ్లెట్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌లకు సంబంధించిన డేటాతో సహా మీ Android TV పరికరం కాల్ లాగ్‌ను సవరించడానికి యాప్‌ని అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను తీసివేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ ఫోన్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌ల గురించిన డేటాతో సహా మీ టాబ్లెట్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌కు సంబంధించిన డేటాతో సహా మీ Android TV పరికరం కాల్ లాగ్‌ను సవరించడానికి యాప్‌ని అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను తీసివేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌ల గురించిన డేటాతో సహా మీ ఫోన్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
     <string name="permlab_bodySensors" msgid="3411035315357380862">"శరీర సెన్సార్‌లను (గుండె స్పందన రేటు మానిటర్‌ల వంటివి) యాక్సెస్ చేయండి"</string>
     <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"మీ శారీరక పరిస్థితిని అనగా మీ గుండె స్పందన రేటు వంటి వాటిని పర్యవేక్షించే సెన్సార్‌ల నుండి డేటాను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_readCalendar" msgid="6408654259475396200">"క్యాలెండర్ ఈవెంట్‌లు మరియు వివరాలను చదవడం"</string>
@@ -464,15 +464,15 @@
     <string name="permdesc_vibrate" msgid="8733343234582083721">"వైబ్రేటర్‌ను నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permdesc_vibrator_state" msgid="7050024956594170724">"వైబ్రేటర్ స్థితిని యాక్సెస్ చేసేందుకు యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_callPhone" msgid="1798582257194643320">"నేరుగా కాల్ చేసే ఫోన్ నంబర్‌లు"</string>
-    <string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
+    <string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్స్‌ రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్స్‌ చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS కాల్ సేవ యాక్సెస్ అనుమతి"</string>
-    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్‌లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్స్‌ చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_readPhoneState" msgid="8138526903259297969">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
     <string name="permdesc_readPhoneState" msgid="7229063553502788058">"పరికరం యొక్క ఫోన్ ఫీచర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
-    <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_callCompanionApp" msgid="3654373653014126884">"సిస్టమ్ ద్వారా కాల్‌లను చూసి, నియంత్రించండి."</string>
-    <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"పరికరంలో కొనసాగుతున్న కాల్‌లను చూడడానికి మరియు నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది. ఇందులో కాల్ కోసం కాల్‌ల నంబర్‌లు మరియు రాష్ట్ర కాల్ వంటి సమాచారం ఉంటుంది."</string>
+    <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
+    <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_callCompanionApp" msgid="3654373653014126884">"సిస్టమ్ ద్వారా కాల్స్‌ను చూసి, నియంత్రించండి."</string>
+    <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"పరికరంలో కొనసాగుతున్న కాల్స్‌ను చూడడానికి మరియు నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది. ఇందులో కాల్ కోసం కాల్స్‌ల నంబర్‌లు మరియు రాష్ట్ర కాల్ వంటి సమాచారం ఉంటుంది."</string>
     <string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"ఆడియో రికార్డ్ పరిమితుల నుండి మినహాయింపు"</string>
     <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"ఆడియోను రికార్డ్ చేయడానికి యాప్‌ను పరిమితుల నుండి మినహాయించండి."</string>
     <string name="permlab_acceptHandover" msgid="2925523073573116523">"మరో యాప్ నుండి కాల్‌ని కొనసాగించండి"</string>
@@ -672,8 +672,8 @@
     <string name="permdesc_sdcardRead" msgid="6872973242228240382">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_sdcardWrite" msgid="4863021819671416668">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను సవరించండి లేదా తొలగించండి"</string>
     <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను రాయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
-    <string name="permlab_use_sip" msgid="8250774565189337477">"SIP కాల్‌లను చేయడానికి/స్వీకరించడానికి"</string>
-    <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్‌లను చేయడానికి మరియు స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permlab_use_sip" msgid="8250774565189337477">"SIP కాల్స్‌ను చేయడానికి/స్వీకరించడానికి"</string>
+    <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్స్‌ను చేయడానికి మరియు స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_register_sim_subscription" msgid="1653054249287576161">"కొత్త టెలికామ్ SIM కనెక్షన్‌లను నమోదు చేయడం"</string>
     <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"కొత్త టెలికామ్ SIM కనెక్షన్‌లను నమోదు చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_register_call_provider" msgid="6135073566140050702">"కొత్త టెలికామ్ కనెక్షన్‌లను నమోదు చేయడం"</string>
@@ -683,7 +683,7 @@
     <string name="permlab_bind_incall_service" msgid="5990625112603493016">"ఇన్-కాల్ స్క్రీన్‌తో పరస్పర చర్య చేయడం"</string>
     <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"వినియోగదారునికి ఇన్-కాల్ స్క్రీన్ ఎప్పుడు, ఎలా కనిపించాలనే దాన్ని నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_bind_connection_service" msgid="5409268245525024736">"టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడం"</string>
-    <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్‌లు చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్స్‌ చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_control_incall_experience" msgid="6436863486094352987">"ఇన్-కాల్ వినియోగదారు అనుభవాన్ని అందించడం"</string>
     <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"ఇన్-కాల్ వినియోగదారుని అనుభవాన్ని అందించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"చారిత్రక నెట్‌వర్క్ వినియోగాన్ని చదవడం"</string>
@@ -693,29 +693,29 @@
     <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"నెట్‌వర్క్ వినియోగ అకౌంటింగ్‌ను సవరించడం"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"యాప్‌లలో నెట్‌వర్క్ వినియోగం ఎలా గణించాలనే దాన్ని సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల ద్వారా ఉపయోగించడానికి ఉద్దేశించినది కాదు."</string>
     <string name="permlab_accessNotifications" msgid="7130360248191984741">"నోటిఫికేషన్‌లను యాక్సెస్ చేయడం"</string>
-    <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్‌లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+    <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్‌లను, ఇతర యాప్‌ల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
     <string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string>
-    <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindDreamService" msgid="4776175992848982706">"డ్రీమ్ సేవ‌కి అనుబంధించడం"</string>
-    <string name="permdesc_bindDreamService" msgid="9129615743300572973">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_bindDreamService" msgid="9129615743300572973">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడం"</string>
-    <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
     <string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడం"</string>
-    <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+    <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
     <string name="permlab_setInputCalibration" msgid="932069700285223434">"ఇన్‌పుట్ పరికరం క్రమాంకనాన్ని మార్చండి"</string>
-    <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM ప్రమాణపత్రాలను యాక్సెస్ చేయడం"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam బదిలీ స్థితిని స్వీకరించడం"</string>
     <string name="permdesc_handoverStatus" msgid="3842269451732571070">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM ప్రమాణపత్రాలను తీసివేయడం"</string>
-    <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"క్యారియర్ సేవలకు అనుబంధించడం"</string>
-    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_access_notification_policy" msgid="5524112842876975537">"అంతరాయం కలిగించవద్దును యాక్సెస్ చేయడం"</string>
     <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
@@ -1259,7 +1259,7 @@
     <string name="app_upgrading_toast" msgid="1016267296049455585">"<xliff:g id="APPLICATION">%1$s</xliff:g>ని అప్‌గ్రేడ్ చేస్తోంది…"</string>
     <string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g>లో <xliff:g id="NUMBER_0">%1$d</xliff:g> యాప్‌ను అనుకూలీకరిస్తోంది."</string>
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g>ని సిద్ధం చేస్తోంది."</string>
-    <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"అనువర్తనాలను ప్రారంభిస్తోంది."</string>
+    <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"యాప్‌లను ప్రారంభిస్తోంది."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"బూట్‌ను ముగిస్తోంది."</string>
     <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"స్క్రీన్‌ను ఆఫ్ చేయాలా?"</string>
     <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"మీ వేలిముద్రను సెటప్ చేస్తున్నప్పుడు, మీరు పవర్ బటన్‌ను నొక్కారు.\n\nఇది సాధారణంగా మీ స్క్రీన్‌ను ఆఫ్ చేస్తుంది."</string>
@@ -1991,7 +1991,7 @@
     <string name="profile_encrypted_detail" msgid="5279730442756849055">"కార్యాలయ ప్రొఫైల్ లాక్ అయింది"</string>
     <string name="profile_encrypted_message" msgid="1128512616293157802">"కార్యాలయ ప్రొఫైల్ అన్‌లాక్ చేయుటకు నొక్కండి"</string>
     <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</string>
-    <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"ఫైల్‌లను వీక్షించడానికి నొక్కండి"</string>
+    <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"ఫైళ్లను వీక్షించడానికి నొక్కండి"</string>
     <string name="pin_target" msgid="8036028973110156895">"పిన్ చేయి"</string>
     <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g>ను పిన్ చేయండి"</string>
     <string name="unpin_target" msgid="3963318576590204447">"అన్‌‌పిన్‌ ‌చేయి"</string>
@@ -2077,8 +2077,8 @@
     <string name="harmful_app_warning_title" msgid="8794823880881113856">"హానికరమైన యాప్ గుర్తించబడింది"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించాలనుకుంటోంది"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
-    <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్‌లు మరియు నోటిఫికేషన్‌లు వైబ్రేట్ అవుతాయి"</string>
-    <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"కాల్‌లు మరియు నోటిఫికేషన్‌లు మ్యూట్ చేయబడతాయి"</string>
+    <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు వైబ్రేట్ అవుతాయి"</string>
+    <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు మ్యూట్ చేయబడతాయి"</string>
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"సిస్టమ్ మార్పులు"</string>
     <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"అంతరాయం కలిగించవద్దు"</string>
     <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"కొత్తది: అంతరాయం కలిగించవద్దు నోటిఫికేషన్‌లను దాస్తోంది"</string>
@@ -2100,7 +2100,7 @@
     <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"సరే"</string>
     <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ఆఫ్ చేయండి"</string>
     <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string>
-    <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్‌లను, మెరుగైన నోటిఫికేషన్‌లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్‌లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్‌లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్‌ను మెరుగైన నోటిఫికేషన్‌లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్‌లకు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్‌ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్‌లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
+    <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్‌లను, మెరుగైన నోటిఫికేషన్‌లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్‌లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్‌లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్‌ను మెరుగైన నోటిఫికేషన్‌లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్స్‌కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్‌ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్‌లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
     <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string>
     <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string>
@@ -2130,7 +2130,7 @@
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"విమానం మోడ్‌లో బ్లూటూత్ ఆన్‌లో ఉంటుంది"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"లోడవుతోంది"</string>
     <plurals name="file_count" formatted="false" msgid="7063513834724389247">
-      <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ఫైల్‌లు</item>
+      <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ఫైళ్లు</item>
       <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ఫైల్</item>
     </plurals>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ఎవరికి షేర్ చేయాలనే దానికి సంబంధించి సిఫార్సులేవీ లేవు"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 78758e8..de5a301 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1950,7 +1950,7 @@
     <string name="maximize_button_text" msgid="4258922519914732645">"بڑا کریں"</string>
     <string name="close_button_text" msgid="10603510034455258">"بند کریں"</string>
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
-    <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب"</string>
+    <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب دیں"</string>
     <string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویڈیو"</string>
     <string name="call_notification_decline_action" msgid="3700345945214000726">"مسترد کریں"</string>
     <string name="call_notification_hang_up_action" msgid="9130720590159188131">"منقطع کر دیں"</string>
diff --git a/core/res/res/values-watch/colors.xml b/core/res/res/values-watch/colors.xml
new file mode 100644
index 0000000..854fbfd
--- /dev/null
+++ b/core/res/res/values-watch/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <!-- Wear Material standard colors -->
+    <color name="wear_material_red_400">#EE675C</color>
+    <color name="wear_material_grey_900">#202124</color>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
index dde8b2e..57c136e 100644
--- a/core/res/res/values-watch/strings.xml
+++ b/core/res/res/values-watch/strings.xml
@@ -25,5 +25,8 @@
         <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. Override from base which says "Body Sensors". [CHAR_LIMIT=25] -->
-    <string name="permgrouplab_sensors">Sensors</string>
-</resources>
+<string name="permgrouplab_sensors">Sensors</string>
+
+
+    <!-- label for item that opens emergency features in the power menu on Wear [CHAR LIMIT=24] -->
+    <string name="global_action_emergency">Emergency SOS</string></resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f99cb19..5cd3138 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -666,6 +666,17 @@
          display is powered on at the same time. -->
     <bool name="config_supportsConcurrentInternalDisplays">true</bool>
 
+    <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
+         "key:value", for example: "0:1".
+          The keys are device states, and the values are one of
+          Settings.Secure.DeviceStateRotationLockSetting.
+          Any device state that doesn't have a default set here will be treated as
+          DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
+          If this map is missing, the feature is disabled and only one global rotation lock setting
+           will apply, regardless of device state. -->
+    <string-array name="config_perDeviceStateRotationLockDefaults" />
+
+
     <!-- Desk dock behavior -->
 
     <!-- The number of degrees to rotate the display when the device is in a desk dock.
@@ -5081,4 +5092,86 @@
 
     <!-- Whether this device should support taking app snapshots on closure -->
     <bool name="config_disableTaskSnapshots">false</bool>
+
+    <!-- The display cutout configs for secondary built-in display. -->
+    <string name="config_secondaryBuiltInDisplayCutout" translatable="false"></string>
+    <string name="config_secondaryBuiltInDisplayCutoutRectApproximation" translatable="false">
+        @string/config_secondaryBuiltInDisplayCutout
+    </string>
+    <bool name="config_fillSecondaryBuiltInDisplayCutout">false</bool>
+    <bool name="config_maskSecondaryBuiltInDisplayCutout">false</bool>
+
+    <!-- An array contains unique ids of all built-in displays and the unique id of a display can be
+         obtained from {@link Display#getUniqueId}. This array should be set for multi-display
+         devices if there are different display related configs(e.g. display cutout, rounded corner)
+         between each built-in display.
+         It is used as an index for multi-display related configs:
+         First look up the index of the unique id of the given built-in display unique id in this
+         array and use this index to get the info in corresponding config arrays such as:
+           - config_displayCutoutPathArray
+           - config_displayCutoutApproximationRectArray
+           - config_fillBuiltInDisplayCutoutArray
+           - config_maskBuiltInDisplayCutoutArray
+           - config_waterfallCutoutArray
+
+         Leave this array empty for single display device and the system will load the default main
+         built-in related configs.
+         -->
+    <string-array name="config_displayUniqueIdArray" translatable="false">
+        <!-- Example:
+        <item>"local:1234567891"</item> // main built-in display
+        <item>"local:1234567892"</item> // secondary built-in display
+        -->
+    </string-array>
+
+    <!-- The display cutout path config for each display in a multi-display device. -->
+    <string-array name="config_displayCutoutPathArray" translatable="false">
+        <item>@string/config_mainBuiltInDisplayCutout</item>
+        <item>@string/config_secondaryBuiltInDisplayCutout</item>
+    </string-array>
+
+    <!-- The display cutout approximation rect config for each display in a multi-display device.
+         -->
+    <string-array name="config_displayCutoutApproximationRectArray" translatable="false">
+        <item>@string/config_mainBuiltInDisplayCutoutRectApproximation</item>
+        <item>@string/config_secondaryBuiltInDisplayCutoutRectApproximation</item>
+    </string-array>
+
+    <!-- The maskBuiltInDisplayCutout config for each display in a multi-display device. -->
+    <array name="config_maskBuiltInDisplayCutoutArray" translatable="false">
+        <item>@bool/config_maskMainBuiltInDisplayCutout</item>
+        <item>@bool/config_maskSecondaryBuiltInDisplayCutout</item>
+    </array>
+
+    <!-- The fillBuiltInDisplayCutout config for each display in a multi-display device. -->
+    <array name="config_fillBuiltInDisplayCutoutArray" translatable="false">
+        <item>@bool/config_fillMainBuiltInDisplayCutout</item>
+        <item>@bool/config_fillSecondaryBuiltInDisplayCutout</item>
+    </array>
+
+    <array name="config_mainBuiltInDisplayWaterfallCutout" translatable="false">
+        <item>@dimen/waterfall_display_left_edge_size</item>
+        <item>@dimen/waterfall_display_top_edge_size</item>
+        <item>@dimen/waterfall_display_right_edge_size</item>
+        <item>@dimen/waterfall_display_bottom_edge_size</item>
+    </array>
+
+    <array name="config_secondaryBuiltInDisplayWaterfallCutout" translatable="false">
+        <item>@dimen/secondary_waterfall_display_left_edge_size</item>
+        <item>@dimen/secondary_waterfall_display_top_edge_size</item>
+        <item>@dimen/secondary_waterfall_display_right_edge_size</item>
+        <item>@dimen/secondary_waterfall_display_bottom_edge_size</item>
+    </array>
+
+    <!-- The waterfall cutout config for each display in a multi-display device. -->
+    <array name="config_waterfallCutoutArray" translatable="false">
+        <item>@array/config_mainBuiltInDisplayWaterfallCutout</item>
+        <item>@array/config_secondaryBuiltInDisplayWaterfallCutout</item>
+    </array>
+
+    <!-- Whether the airplane mode should be reset when device boots in non-safemode after exiting
+         from safemode.
+         This flag should be enabled only when the product does not have any UI to toggle airplane
+         mode like automotive devices.-->
+    <bool name="config_autoResetAirplaneMode">false</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index de7a117..e8bb606 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -237,6 +237,9 @@
          value is calculated in ConversationLayout#updateActionListPadding() -->
     <dimen name="notification_actions_padding_start">36dp</dimen>
 
+    <!-- The max width of a priority action button when it is collapsed to just the icon. -->
+    <dimen name="notification_actions_collapsed_priority_width">60dp</dimen>
+
     <!-- The start padding to optionally use (e.g. if there's extra space) for CallStyle
          notification actions.
          this = conversation_content_start (80dp) - button inset (4dp) - action padding (12dp) -->
@@ -920,7 +923,7 @@
 
     <dimen name="chooser_action_button_icon_size">18dp</dimen>
 
-    <!-- For Waterfall Display -->
+    <!-- For main built-in Waterfall Display -->
     <dimen name="waterfall_display_left_edge_size">0px</dimen>
     <dimen name="waterfall_display_top_edge_size">0px</dimen>
     <dimen name="waterfall_display_right_edge_size">0px</dimen>
@@ -943,4 +946,10 @@
     <dimen name="starting_surface_icon_size">160dp</dimen>
     <!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
     <dimen name="starting_surface_default_icon_size">108dp</dimen>
+
+    <!-- For secondary built-in Waterfall Display -->
+    <dimen name="secondary_waterfall_display_left_edge_size">0px</dimen>
+    <dimen name="secondary_waterfall_display_top_edge_size">0px</dimen>
+    <dimen name="secondary_waterfall_display_right_edge_size">0px</dimen>
+    <dimen name="secondary_waterfall_display_bottom_edge_size">0px</dimen>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1084963..0daf358 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2218,6 +2218,7 @@
   <java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
   <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
   <java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
+  <java-symbol type="bool" name="config_autoResetAirplaneMode" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -3184,6 +3185,7 @@
 
   <java-symbol type="id" name="notification_action_list_margin_target" />
   <java-symbol type="dimen" name="notification_actions_padding_start"/>
+  <java-symbol type="dimen" name="notification_actions_collapsed_priority_width"/>
   <java-symbol type="dimen" name="notification_action_disabled_alpha" />
   <java-symbol type="id" name="tag_margin_end_when_icon_visible" />
   <java-symbol type="id" name="tag_margin_end_when_icon_gone" />
@@ -3839,6 +3841,8 @@
   <java-symbol type="string" name="config_foldedArea" />
   <java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
   <java-symbol type="bool" name="config_unfoldTransitionEnabled" />
+  <java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
+
 
   <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
   <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
@@ -4443,4 +4447,26 @@
   <java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
 
   <java-symbol type="bool" name="config_disableTaskSnapshots" />
+
+  <java-symbol type="string" name="config_secondaryBuiltInDisplayCutout" />
+  <java-symbol type="string" name="config_secondaryBuiltInDisplayCutoutRectApproximation" />
+  <java-symbol type="bool" name="config_fillSecondaryBuiltInDisplayCutout" />
+  <java-symbol type="bool" name="config_maskSecondaryBuiltInDisplayCutout" />
+  <java-symbol type="array" name="config_displayUniqueIdArray" />
+  <java-symbol type="array" name="config_displayCutoutPathArray" />
+  <java-symbol type="array" name="config_displayCutoutApproximationRectArray" />
+  <java-symbol type="array" name="config_fillBuiltInDisplayCutoutArray" />
+  <java-symbol type="array" name="config_maskBuiltInDisplayCutoutArray" />
+  <java-symbol type="dimen" name="secondary_waterfall_display_left_edge_size" />
+  <java-symbol type="dimen" name="secondary_waterfall_display_top_edge_size" />
+  <java-symbol type="dimen" name="secondary_waterfall_display_right_edge_size" />
+  <java-symbol type="dimen" name="secondary_waterfall_display_bottom_edge_size" />
+  <java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
+  <java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
+  <java-symbol type="array" name="config_waterfallCutoutArray" />
+
+  <java-symbol type="fraction" name="global_actions_vertical_padding_percentage" />
+  <java-symbol type="fraction" name="global_actions_horizontal_padding_percentage" />
+  <java-symbol type="drawable" name="global_actions_item_red_background" />
+  <java-symbol type="color" name="wear_material_grey_900" />
 </resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 2be5c47..37d059a 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -88,9 +88,12 @@
     <!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
     <shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
 
-    <!-- Czechia: 7-8 digits, starting with 9, plus EU:
-         http://www.o2.cz/osobni/en/services-by-alphabet/91670-premium_sms.html -->
-    <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
+    <!-- Czechia: Premium numbers start with 90, and are either 5 or 7 digits (5 digits is a
+         subscription request, you will be charged for the messages received, but it's necessary
+         to warn on the _request_ as that's the last chance to stop), plus EU:
+         https://www.t-mobile.cz/platebni-a-premium-sms
+         https://www.vodafone.cz/pece/vyuctovani-platby-kredit/platby-mobilem/cena-premium-sms/ -->
+    <shortcode country="cz" premium="90\\d{5}|90\\d{3}" free="116\\d{3}" />
 
     <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
     <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296|83782|3011|73240|72438" />
diff --git a/core/tests/BroadcastRadioTests/OWNERS b/core/tests/BroadcastRadioTests/OWNERS
index ea4421e..3e360e7 100644
--- a/core/tests/BroadcastRadioTests/OWNERS
+++ b/core/tests/BroadcastRadioTests/OWNERS
@@ -1,2 +1,3 @@
+keunyoung@google.com
+oscarazu@google.com
 twasilczyk@google.com
-randolphs@google.com
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index 7c6271c..c194989 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -65,6 +65,7 @@
     @Mock ITunerSession mHalTunerSessionMock;
     private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
 
+    private final Object mLock = new Object();
     // RadioModule under test
     private RadioModule mRadioModule;
 
@@ -96,7 +97,7 @@
 
         mRadioModule = new RadioModule(mBroadcastRadioMock, new RadioManager.ModuleProperties(0, "",
                   0, "", "", "", "", 0, 0, false, false, null, false, new int[] {}, new int[] {},
-                  null, null));
+                  null, null), mLock);
 
         doAnswer((Answer) invocation -> {
             mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index fb820cb..6f17ea9 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -286,7 +286,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 194242735)
     public void testHandleActivityConfigurationChanged_EnsureUpdatesProcessedInOrder()
             throws Exception {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index 4609c23..0e5f2e1 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -26,6 +26,7 @@
 import android.app.assist.AssistStructure.ViewNodeBuilder;
 import android.app.assist.AssistStructure.ViewNodeParcelable;
 import android.content.Context;
+import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.SystemClock;
 import android.text.InputFilter;
@@ -244,6 +245,34 @@
         assertBigView(clone.getViewNode());
     }
 
+    @Test
+    public void testViewNodeParcelableControlFlags() {
+        View view = newBigView();
+        mActivity.addView(view);
+        waitUntilViewsAreLaidOff();
+
+        assertThat(view.getViewRootImpl()).isNotNull();
+        ViewNodeBuilder viewStructure = new ViewNodeBuilder();
+        viewStructure.setAutofillId(view.getAutofillId());
+        view.onProvideAutofillStructure(viewStructure, /* flags= */ 0);
+
+        // Set highest and lowest control flags
+        viewStructure.setReceiveContentMimeTypes(new String[] {});
+        viewStructure.setLocaleList(new LocaleList());
+
+        ViewNodeParcelable viewNodeParcelable = new ViewNodeParcelable(viewStructure.getViewNode());
+
+        // Check properties on "original" view node.
+        assertBigView(viewNodeParcelable.getViewNode());
+        assertControlFlags(viewNodeParcelable.getViewNode());
+
+        // Check properties on "cloned" view node.
+        ViewNodeParcelable clone = cloneThroughParcel(viewNodeParcelable);
+        assertBigView(clone.getViewNode());
+        assertControlFlags(clone.getViewNode());
+
+    }
+
     private EditText newSmallView() {
         EditText view = new EditText(mContext);
         view.setText("I AM GROOT");
@@ -297,6 +326,20 @@
         assertThat(hint.charAt(BIG_VIEW_SIZE - 1)).isEqualTo(BIG_VIEW_CHAR);
     }
 
+    /**
+     * Assert the lowest and highest bit control flags.
+     *
+     * The lowest and highest flags are {@link ViewNode#FLAGS_HAS_LOCALE_LIST} and
+     * {@link ViewNode#FLAGS_HAS_MIME_TYPES} respectively, so we check these two during parceling to
+     * make sure the entire range of control flags are copied.
+     *
+     * TODO: Need to change this test if the flag bits are added/changed in the future.
+     */
+    private void assertControlFlags(ViewNode view) {
+        assertThat(view.getReceiveContentMimeTypes()).isNotNull();
+        assertThat(view.getLocaleList()).isNotNull();
+    }
+
     private ViewNodeParcelable cloneThroughParcel(ViewNodeParcelable viewNodeParcelable) {
         Parcel parcel = Parcel.obtain();
 
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 08edb4e..bc92da9 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -16,6 +16,8 @@
 
 package android.app.backup;
 
+import static android.app.backup.FullBackup.ConfigSection.CLOUD_BACKUP;
+
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
 import android.content.Context;
 import android.test.AndroidTestCase;
@@ -414,6 +416,37 @@
         assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
     }
 
+    public void testParseNewBackupSchemeFromXml_emptyCloudSectionIsRespected() throws Exception {
+        mXpp.setInput(new StringReader(
+                "<data-extraction-rules>" +
+                        "<cloud-backup>" +
+                        "</cloud-backup>" +
+                        "</data-extraction-rules>"));
+
+        FullBackup.BackupScheme backupScheme = FullBackup.getBackupSchemeForTest(mContext);
+        boolean result = backupScheme.parseNewBackupSchemeFromXmlLocked(mXpp, CLOUD_BACKUP,
+                excludesSet, includeMap);
+
+        assertTrue(result);
+    }
+
+    public void testParseNewBackupSchemeFromXml_emptyCloudSectionWithEncryptionFlagIsRespected()
+            throws Exception {
+        mXpp.setInput(new StringReader(
+                "<data-extraction-rules>" +
+                        "<cloud-backup disableIfNoEncryptionCapabilities=\"true\">" +
+                        "</cloud-backup>" +
+                        "</data-extraction-rules>"));
+
+        FullBackup.BackupScheme backupScheme = FullBackup.getBackupSchemeForTest(mContext);
+        boolean result = backupScheme.parseNewBackupSchemeFromXmlLocked(mXpp, CLOUD_BACKUP,
+                excludesSet, includeMap);
+
+        assertTrue(result);
+        assertEquals(backupScheme.getRequiredTransportFlags(),
+                BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED);
+    }
+
     public void testDoubleDotInPath_isIgnored() throws Exception {
         mXpp.setInput(new StringReader(
                 "<full-backup-content>" +
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 9915e38..50639be 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -156,7 +156,8 @@
                 .setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
                 .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
                 .setIsForward(true).setAssistToken(assistToken)
-                .setShareableActivityToken(shareableActivityToken).build();
+                .setShareableActivityToken(shareableActivityToken)
+                .setTaskFragmentToken(new Binder()).build();
 
         LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
         LaunchActivityItem item = itemSupplier.get();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 75da0bf..1173c92 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -112,6 +112,7 @@
         private IBinder mShareableActivityToken;
         private FixedRotationAdjustments mFixedRotationAdjustments;
         private boolean mLaunchedFromBubble;
+        private IBinder mTaskFragmentToken;
 
         LaunchActivityItemBuilder setIntent(Intent intent) {
             mIntent = intent;
@@ -213,13 +214,18 @@
             return this;
         }
 
+        LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) {
+            mTaskFragmentToken = taskFragmentToken;
+            return this;
+        }
+
         LaunchActivityItem build() {
             return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
                     mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
                     mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
                     mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
                     null /* activityClientController */, mFixedRotationAdjustments,
-                    mShareableActivityToken, mLaunchedFromBubble);
+                    mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index df0c64c..98c9afd 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -209,6 +209,7 @@
                 .setPendingNewIntents(referrerIntentList()).setIsForward(true)
                 .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
                 .setShareableActivityToken(new Binder())
+                .setTaskFragmentToken(new Binder())
                 .build();
 
         writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/view/ViewInputConnectionTest.java b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
index d667af3..d60c0c6 100644
--- a/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
+++ b/core/tests/coretests/src/android/view/ViewInputConnectionTest.java
@@ -19,13 +19,25 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.annotation.DurationMillisLong;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Color;
+import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.text.InputType;
 import android.text.format.DateUtils;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
@@ -45,12 +57,23 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
 /**
  * Tests for internal APIs/behaviors of {@link View} and {@link InputConnection}.
  */
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class ViewInputConnectionTest {
+    @DurationMillisLong
+    private static final long TIMEOUT = 5000;
+    @DurationMillisLong
+    private static final long EXPECTED_TIMEOUT = 500;
+
     @Rule
     public ActivityTestRule<ViewInputConnectionTestActivity> mActivityRule =
             new ActivityTestRule<>(ViewInputConnectionTestActivity.class);
@@ -289,4 +312,282 @@
             super.onInputConnectionClosedInternal();
         }
     }
+
+
+    @Test
+    public void testInputConnectionCallbacks_nonUiThread() throws Throwable {
+        try (InputConnectionHandlingThread thread = new InputConnectionHandlingThread()) {
+            final ViewGroup viewGroup = getOnMainSync(() -> mActivity.findViewById(R.id.root));
+            final TestOffThreadEditor editor = getOnMainSync(() -> {
+                final TestOffThreadEditor myEditor =
+                        new TestOffThreadEditor(viewGroup.getContext(), thread.getHandler());
+                viewGroup.addView(myEditor);
+                myEditor.requestFocus();
+                return myEditor;
+            });
+
+            mInstrumentation.waitForIdleSync();
+
+            assertThat(editor.mOnCreateInputConnectionCalled.await(TIMEOUT, TimeUnit.MILLISECONDS))
+                    .isTrue();
+
+            // Invalidate the currently used InputConnection by moving the focus to a new EditText.
+            mActivityRule.runOnUiThread(() -> {
+                final EditText editText = new EditText(viewGroup.getContext());
+                viewGroup.addView(editText);
+                editText.requestFocus();
+            });
+
+            // Make sure that InputConnection#closeConnection() gets called on the handler thread.
+            assertThat(editor.mInputConnectionClosedCalled.await(TIMEOUT, TimeUnit.MILLISECONDS))
+                    .isTrue();
+            assertThat(editor.mInputConnectionClosedCallingThreadId.get())
+                    .isEqualTo(thread.getThreadId());
+
+            // Make sure that View#onInputConnectionClosed() is not yet dispatched, because
+            // InputConnection#closeConnection() is still blocked.
+            assertThat(editor.mOnInputConnectionClosedCalled.await(
+                    EXPECTED_TIMEOUT, TimeUnit.MILLISECONDS)).isFalse();
+
+            // Unblock InputConnection#closeConnection()
+            editor.mInputConnectionClosedBlocker.countDown();
+
+            // Make sure that View#onInputConnectionClosed() is dispatched on the main thread.
+            assertThat(editor.mOnInputConnectionClosedCalled.await(TIMEOUT, TimeUnit.MILLISECONDS))
+                    .isTrue();
+            assertThat(editor.mInputConnectionClosedBlockerTimedOut.get()).isFalse();
+            assertThat(editor.mOnInputConnectionClosedCallingThreadId.get())
+                    .isEqualTo(getOnMainSync(Process::myTid));
+        }
+    }
+
+    private <T> T getOnMainSync(@NonNull Supplier<T> supplier) throws Throwable {
+        final AtomicReference<T> result = new AtomicReference<>();
+        mActivityRule.runOnUiThread(() -> result.set(supplier.get()));
+        return result.get();
+    }
+
+    private static class TestOffThreadEditor extends View {
+        private static final int TEST_VIEW_HEIGHT = 10;
+
+        public CountDownLatch mOnCreateInputConnectionCalled = new CountDownLatch(1);
+        public CountDownLatch mInputConnectionClosedCalled = new CountDownLatch(1);
+        public CountDownLatch mInputConnectionClosedBlocker = new CountDownLatch(1);
+        public AtomicBoolean mInputConnectionClosedBlockerTimedOut = new AtomicBoolean();
+        public AtomicReference<Integer> mInputConnectionClosedCallingThreadId =
+                new AtomicReference<>();
+
+        public CountDownLatch mOnInputConnectionClosedCalled = new CountDownLatch(1);
+        public AtomicReference<Integer> mOnInputConnectionClosedCallingThreadId =
+                new AtomicReference<>();
+
+        private final Handler mInputConnectionHandler;
+
+        TestOffThreadEditor(Context context, @NonNull Handler inputConnectionHandler) {
+            super(context);
+            setBackgroundColor(Color.YELLOW);
+            setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, TEST_VIEW_HEIGHT));
+            setFocusableInTouchMode(true);
+            setFocusable(true);
+            mInputConnectionHandler = inputConnectionHandler;
+        }
+
+        @Override
+        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+            mOnCreateInputConnectionCalled.countDown();
+            outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
+            return new NoOpInputConnection() {
+                @Override
+                public Handler getHandler() {
+                    return mInputConnectionHandler;
+                }
+
+                @Override
+                public void closeConnection() {
+                    mInputConnectionClosedCallingThreadId.compareAndSet(null, Process.myTid());
+                    mInputConnectionClosedCalled.countDown();
+                    try {
+                        if (mInputConnectionClosedBlocker.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                            return;
+                        }
+                    } catch (InterruptedException e) {
+                    }
+                    mInputConnectionClosedBlockerTimedOut.set(true);
+                }
+            };
+        }
+
+        @Override
+        public boolean onCheckIsTextEditor() {
+            return true;
+        }
+
+        @Override
+        public void onInputConnectionClosedInternal() {
+            mOnInputConnectionClosedCallingThreadId.compareAndSet(null, Process.myTid());
+            mOnInputConnectionClosedCalled.countDown();
+            super.onInputConnectionClosedInternal();
+        }
+    }
+
+    static class NoOpInputConnection implements InputConnection {
+
+        @Override
+        public CharSequence getTextBeforeCursor(int n, int flags) {
+            return null;
+        }
+
+        @Override
+        public CharSequence getTextAfterCursor(int n, int flags) {
+            return null;
+        }
+
+        @Override
+        public CharSequence getSelectedText(int flags) {
+            return null;
+        }
+
+        @Override
+        public int getCursorCapsMode(int reqModes) {
+            return 0;
+        }
+
+        @Override
+        public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+            return null;
+        }
+
+        @Override
+        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+            return false;
+        }
+
+        @Override
+        public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+            return false;
+        }
+
+        @Override
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+
+        @Override
+        public boolean setComposingRegion(int start, int end) {
+            return false;
+        }
+
+        @Override
+        public boolean finishComposingText() {
+            return false;
+        }
+
+        @Override
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            return false;
+        }
+
+        @Override
+        public boolean commitCompletion(CompletionInfo text) {
+            return false;
+        }
+
+        @Override
+        public boolean commitCorrection(CorrectionInfo correctionInfo) {
+            return false;
+        }
+
+        @Override
+        public boolean setSelection(int start, int end) {
+            return false;
+        }
+
+        @Override
+        public boolean performEditorAction(int editorAction) {
+            return false;
+        }
+
+        @Override
+        public boolean performContextMenuAction(int id) {
+            return false;
+        }
+
+        @Override
+        public boolean beginBatchEdit() {
+            return false;
+        }
+
+        @Override
+        public boolean endBatchEdit() {
+            return false;
+        }
+
+        @Override
+        public boolean sendKeyEvent(KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean clearMetaKeyStates(int states) {
+            return false;
+        }
+
+        @Override
+        public boolean reportFullscreenMode(boolean enabled) {
+            return false;
+        }
+
+        @Override
+        public boolean performPrivateCommand(String action, Bundle data) {
+            return false;
+        }
+
+        @Override
+        public boolean requestCursorUpdates(int cursorUpdateMode) {
+            return false;
+        }
+
+        @Override
+        public Handler getHandler() {
+            return null;
+        }
+
+        @Override
+        public void closeConnection() {
+
+        }
+
+        @Override
+        public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+            return false;
+        }
+    }
+
+    private static final class InputConnectionHandlingThread extends HandlerThread
+            implements AutoCloseable {
+
+        private final Handler mHandler;
+
+        InputConnectionHandlingThread() {
+            super("IC-callback");
+            start();
+            mHandler = Handler.createAsync(getLooper());
+        }
+
+        @NonNull
+        Handler getHandler() {
+            return mHandler;
+        }
+
+        @Override
+        public void close() {
+            quitSafely();
+            try {
+                join(TIMEOUT);
+            } catch (InterruptedException e) {
+                fail("Failed to stop the thread: " + e);
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputConnectionCommandTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputConnectionCommandTest.java
deleted file mode 100644
index efe6cec..0000000
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputConnectionCommandTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import static org.junit.Assert.assertThrows;
-
-import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class InputConnectionCommandTest {
-    @Test
-    public void testCreateFromParcelDoesNotSwallowExceptions() {
-        final Parcel parcel = Parcel.obtain();
-        try {
-            parcel.writeInt(InputConnectionCommandType.FIRST_COMMAND);
-            parcel.writeInt(InputConnectionCommand.FieldMask.PARCELABLE);
-            parcel.writeInt(InputConnectionCommand.ParcelableType.NULL);  // invalid
-            assertThrows(RuntimeException.class,
-                    () -> InputConnectionCommand.CREATOR.createFromParcel(parcel));
-        } finally {
-            parcel.recycle();
-        }
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
index 9de09d6..32bfdcb 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
@@ -73,13 +73,4 @@
                 InputMethodDebug.softInputDisplayReasonToString(
                         SoftInputShowHideReason.HIDE_REMOVE_CLIENT));
     }
-
-    @Test
-    public void testDumpInputConnectionCommand() {
-        // TODO: add more tests
-        assertEquals("null", InputMethodDebug.dumpInputConnectionCommand(null));
-        assertEquals("endBatchEdit()",
-                InputMethodDebug.dumpInputConnectionCommand(
-                        InputConnectionCommand.create(InputConnectionCommandType.END_BATCH_EDIT)));
-    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 96b4316..7cd8197 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -23,6 +23,7 @@
 import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
 import static com.android.internal.jank.FrameTracker.ViewRootWrapper;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_WALLPAPER_TRANSITION;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -50,6 +51,7 @@
 import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
 import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
 import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.jank.InteractionJankMonitor.Session;
 
 import org.junit.Before;
@@ -69,7 +71,6 @@
     public ActivityTestRule<ViewAttachTestActivity> mRule =
             new ActivityTestRule<>(ViewAttachTestActivity.class);
 
-    private FrameTracker mTracker;
     private ThreadedRendererWrapper mRenderer;
     private FrameMetricsWrapper mWrapper;
     private SurfaceControlWrapper mSurfaceControlWrapper;
@@ -85,7 +86,6 @@
         View view = mActivity.getWindow().getDecorView();
         assertThat(view.isAttachedToWindow()).isTrue();
 
-        Handler handler = mRule.getActivity().getMainThreadHandler();
         mWrapper = Mockito.spy(new FrameMetricsWrapper());
         mRenderer = Mockito.spy(new ThreadedRendererWrapper(view.getThreadedRenderer()));
         doNothing().when(mRenderer).addObserver(any());
@@ -103,229 +103,355 @@
                 mListenerCapture.capture());
 
         mChoreographer = mock(ChoreographerWrapper.class);
+    }
 
-        Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
-        mTracker = Mockito.spy(
+    private FrameTracker spyFrameTracker(int cuj, String postfix, boolean surfaceOnly) {
+        Handler handler = mRule.getActivity().getMainThreadHandler();
+        Session session = new Session(cuj, postfix);
+        Configuration config = mock(Configuration.class);
+        when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
+        when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
+        FrameTracker frameTracker = Mockito.spy(
                 new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
                         mSurfaceControlWrapper, mChoreographer, mWrapper,
-                        /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1,
-                        null));
-        doNothing().when(mTracker).triggerPerfetto();
-        doNothing().when(mTracker).postTraceStartMarker();
+                        /* traceThresholdMissedFrames= */ 1,
+                        /* traceThresholdFrameTimeMillis= */ -1,
+                        /* FrameTrackerListener= */ null, config));
+        doNothing().when(frameTracker).triggerPerfetto();
+        doNothing().when(frameTracker).postTraceStartMarker();
+        return frameTracker;
     }
 
     @Test
     public void testOnlyFirstWindowFrameOverThreshold() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         // Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
         when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
                 .then(unusedInvocation -> System.nanoTime());
 
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // send first frame with a long duration - should not be taken into account
-        sendFirstWindowFrame(100, JANK_APP_DEADLINE_MISSED, 100L);
+        sendFirstWindowFrame(tracker, 100, JANK_APP_DEADLINE_MISSED, 100L);
 
         // send another frame with a short duration - should not be considered janky
-        sendFirstWindowFrame(5, JANK_NONE, 101L);
+        sendFirstWindowFrame(tracker, 5, JANK_NONE, 101L);
 
         // end the trace session, the last janky frame is after the end() so is discarded.
         when(mChoreographer.getVsyncId()).thenReturn(102L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        sendFrame(5, JANK_NONE, 102L);
-        sendFrame(500, JANK_APP_DEADLINE_MISSED, 103L);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        sendFrame(tracker, 5, JANK_NONE, 102L);
+        sendFrame(tracker, 500, JANK_APP_DEADLINE_MISSED, 103L);
 
-        verify(mTracker).removeObservers();
-        verify(mTracker, never()).triggerPerfetto();
+        verify(tracker).removeObservers();
+        verify(tracker, never()).triggerPerfetto();
     }
 
     @Test
     public void testSfJank() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // send first frame - not janky
-        sendFrame(4, JANK_NONE, 100L);
+        sendFrame(tracker, 4, JANK_NONE, 100L);
 
         // send another frame - should be considered janky
-        sendFrame(40, JANK_SURFACEFLINGER_DEADLINE_MISSED, 101L);
+        sendFrame(tracker, 40, JANK_SURFACEFLINGER_DEADLINE_MISSED, 101L);
 
         // end the trace session
         when(mChoreographer.getVsyncId()).thenReturn(102L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        sendFrame(4, JANK_NONE, 102L);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        sendFrame(tracker, 4, JANK_NONE, 102L);
 
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
-        verify(mTracker).triggerPerfetto();
+        verify(tracker).triggerPerfetto();
     }
 
     @Test
     public void testFirstFrameJankyNoTrigger() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // send first frame - janky
-        sendFrame(40, JANK_APP_DEADLINE_MISSED, 100L);
+        sendFrame(tracker, 40, JANK_APP_DEADLINE_MISSED, 100L);
 
         // send another frame - not jank
-        sendFrame(4, JANK_NONE, 101L);
+        sendFrame(tracker, 4, JANK_NONE, 101L);
 
         // end the trace session
         when(mChoreographer.getVsyncId()).thenReturn(102L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        sendFrame(4, JANK_NONE, 102L);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        sendFrame(tracker, 4, JANK_NONE, 102L);
 
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
-        verify(mTracker, never()).triggerPerfetto();
+        verify(tracker, never()).triggerPerfetto();
     }
 
     @Test
     public void testOtherFrameOverThreshold() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // send first frame - not janky
-        sendFrame(4, JANK_NONE, 100L);
+        sendFrame(tracker, 4, JANK_NONE, 100L);
 
         // send another frame - should be considered janky
-        sendFrame(40, JANK_APP_DEADLINE_MISSED, 101L);
+        sendFrame(tracker, 40, JANK_APP_DEADLINE_MISSED, 101L);
 
         // end the trace session
         when(mChoreographer.getVsyncId()).thenReturn(102L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        sendFrame(4, JANK_NONE, 102L);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        sendFrame(tracker, 4, JANK_NONE, 102L);
 
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
-        verify(mTracker).triggerPerfetto();
+        verify(tracker).triggerPerfetto();
     }
 
     @Test
     public void testLastFrameOverThresholdBeforeEnd() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // send first frame - not janky
-        sendFrame(4, JANK_NONE, 100L);
+        sendFrame(tracker, 4, JANK_NONE, 100L);
 
         // send another frame - not janky
-        sendFrame(4, JANK_NONE, 101L);
+        sendFrame(tracker, 4, JANK_NONE, 101L);
 
         // end the trace session, simulate one more valid callback came after the end call.
         when(mChoreographer.getVsyncId()).thenReturn(102L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        sendFrame(50, JANK_APP_DEADLINE_MISSED, 102L);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 102L);
 
         // One more callback with VSYNC after the end() vsync id.
-        sendFrame(4, JANK_NONE, 103L);
+        sendFrame(tracker, 4, JANK_NONE, 103L);
 
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // We detected a janky frame - trigger Perfetto
-        verify(mTracker).triggerPerfetto();
+        verify(tracker).triggerPerfetto();
     }
 
     @Test
     public void testBeginCancel() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer).addObserver(any());
 
         // First frame - not janky
-        sendFrame(4, JANK_NONE, 100L);
+        sendFrame(tracker, 4, JANK_NONE, 100L);
 
         // normal frame - not janky
-        sendFrame(4, JANK_NONE, 101L);
+        sendFrame(tracker, 4, JANK_NONE, 101L);
 
         // a janky frame
-        sendFrame(50, JANK_APP_DEADLINE_MISSED, 102L);
+        sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 102L);
 
-        mTracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
-        verify(mTracker).removeObservers();
+        tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+        verify(tracker).removeObservers();
         // Since the tracker has been cancelled, shouldn't trigger perfetto.
-        verify(mTracker, never()).triggerPerfetto();
+        verify(tracker, never()).triggerPerfetto();
     }
 
     @Test
     public void testCancelIfEndVsyncIdEqualsToBeginVsyncId() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // end the trace session
         when(mChoreographer.getVsyncId()).thenReturn(101L);
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
 
         // Since the begin vsync id (101) equals to the end vsync id (101), will be treat as cancel.
-        verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
+        verify(tracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
 
         // Observers should be removed in this case, or FrameTracker object will be leaked.
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // Should never trigger Perfetto since it is a cancel.
-        verify(mTracker, never()).triggerPerfetto();
+        verify(tracker, never()).triggerPerfetto();
     }
 
     @Test
     public void testCancelIfEndVsyncIdLessThanBeginVsyncId() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
         when(mChoreographer.getVsyncId()).thenReturn(100L);
-        mTracker.begin();
+        tracker.begin();
         verify(mRenderer, only()).addObserver(any());
 
         // end the trace session at the same vsync id, end vsync id will less than the begin one.
         // Because the begin vsync id is supposed to the next frame,
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
+        tracker.end(FrameTracker.REASON_END_NORMAL);
 
         // The begin vsync id (101) is larger than the end one (100), will be treat as cancel.
-        verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
+        verify(tracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
 
         // Observers should be removed in this case, or FrameTracker object will be leaked.
-        verify(mTracker).removeObservers();
+        verify(tracker).removeObservers();
 
         // Should never trigger Perfetto since it is a cancel.
-        verify(mTracker, never()).triggerPerfetto();
+        verify(tracker, never()).triggerPerfetto();
     }
 
     @Test
     public void testCancelWhenSessionNeverBegun() {
-        mTracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
-        verify(mTracker).removeObservers();
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
+        tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+        verify(tracker).removeObservers();
     }
 
     @Test
     public void testEndWhenSessionNeverBegun() {
-        mTracker.end(FrameTracker.REASON_END_NORMAL);
-        verify(mTracker).removeObservers();
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
+        tracker.end(FrameTracker.REASON_END_NORMAL);
+        verify(tracker).removeObservers();
     }
 
-    private void sendFirstWindowFrame(long durationMillis,
+    @Test
+    public void testSurfaceOnlyOtherFrameJanky() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+        when(mChoreographer.getVsyncId()).thenReturn(100L);
+        tracker.begin();
+        verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+        // First frame - not janky
+        sendFrame(tracker, JANK_NONE, 100L);
+        // normal frame - not janky
+        sendFrame(tracker, JANK_NONE, 101L);
+        // a janky frame
+        sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 102L);
+
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
+        tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+        // an extra frame to trigger finish
+        sendFrame(tracker, JANK_NONE, 103L);
+
+        verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+        verify(tracker).triggerPerfetto();
+    }
+
+    @Test
+    public void testSurfaceOnlyFirstFrameJanky() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+        when(mChoreographer.getVsyncId()).thenReturn(100L);
+        tracker.begin();
+        verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+        // First frame - janky
+        sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 100L);
+        // normal frame - not janky
+        sendFrame(tracker, JANK_NONE, 101L);
+        // normal frame - not janky
+        sendFrame(tracker, JANK_NONE, 102L);
+
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
+        tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+        // an extra frame to trigger finish
+        sendFrame(tracker, JANK_NONE, 103L);
+
+        verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+        verify(tracker, never()).triggerPerfetto();
+    }
+
+    @Test
+    public void testSurfaceOnlyLastFrameJanky() {
+        FrameTracker tracker = spyFrameTracker(
+                CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+        when(mChoreographer.getVsyncId()).thenReturn(100L);
+        tracker.begin();
+        verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+        // First frame - not janky
+        sendFrame(tracker, JANK_NONE, 100L);
+        // normal frame - not janky
+        sendFrame(tracker, JANK_NONE, 101L);
+        // normal frame - not janky
+        sendFrame(tracker, JANK_NONE, 102L);
+
+        when(mChoreographer.getVsyncId()).thenReturn(102L);
+        tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+        // janky frame, should be ignored, trigger finish
+        sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 103L);
+
+        verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+        verify(tracker, never()).triggerPerfetto();
+    }
+
+    private void sendFirstWindowFrame(FrameTracker tracker, long durationMillis,
             @JankType int jankType, long vsyncId) {
-        sendFrame(durationMillis, jankType, vsyncId, true /* firstWindowFrame */);
+        sendFrame(tracker, durationMillis, jankType, vsyncId, /* firstWindowFrame= */ true);
     }
 
-    private void sendFrame(long durationMillis,
+    private void sendFrame(FrameTracker tracker, long durationMillis,
             @JankType int jankType, long vsyncId) {
-        sendFrame(durationMillis, jankType, vsyncId, false /* firstWindowFrame */);
+        sendFrame(tracker, durationMillis, jankType, vsyncId, /* firstWindowFrame= */ false);
     }
 
-    private void sendFrame(long durationMillis,
+    /**
+     * Used for surface only test.
+     */
+    private void sendFrame(FrameTracker tracker, @JankType int jankType, long vsyncId) {
+        sendFrame(tracker, /* durationMillis= */ -1,
+                jankType, vsyncId, /* firstWindowFrame= */ false);
+    }
+
+    private void sendFrame(FrameTracker tracker, long durationMillis,
             @JankType int jankType, long vsyncId, boolean firstWindowFrame) {
-        when(mWrapper.getTiming()).thenReturn(new long[] { 0, vsyncId });
-        doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
-                .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
-        doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
-                .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
-        mTracker.onFrameMetricsAvailable(0);
+        if (!tracker.mSurfaceOnly) {
+            when(mWrapper.getTiming()).thenReturn(new long[]{0, vsyncId});
+            doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
+                    .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+            doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+                    .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+            tracker.onFrameMetricsAvailable(0);
+        }
         mListenerCapture.getValue().onJankDataAvailable(new JankData[] {
                 new JankData(vsyncId, jankType)
         });
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index c153b38..d7a5e26 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.jank;
 
-import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
-import static com.android.internal.jank.FrameTracker.ViewRootWrapper;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
 
@@ -25,17 +23,17 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.Message;
 import android.provider.DeviceConfig;
 import android.view.View;
 import android.view.ViewAttachTestActivity;
@@ -43,8 +41,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.rule.ActivityTestRule;
 
+import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
 import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
 import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.FrameTracker.ViewRootWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.jank.InteractionJankMonitor.Session;
 
 import org.junit.Before;
@@ -92,12 +94,15 @@
         verify(mWorker).start();
 
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
+        Configuration config = mock(Configuration.class);
+        when(config.isSurfaceOnly()).thenReturn(false);
         FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
                 new ThreadedRendererWrapper(mView.getThreadedRenderer()),
-                new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
-                mock(FrameTracker.ChoreographerWrapper.class),
-                new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
-                /*traceThresholdFrameTimeMillis=*/ -1, null));
+                new ViewRootWrapper(mView.getViewRootImpl()),
+                new SurfaceControlWrapper(), mock(ChoreographerWrapper.class),
+                new FrameMetricsWrapper(),
+                /* traceThresholdMissedFrames= */ 1, /* traceThresholdFrameTimeMillis= */ -1,
+                /* FrameTrackerListener */ null, config));
         doReturn(tracker).when(monitor).createFrameTracker(any(), any());
         doNothing().when(tracker).triggerPerfetto();
         doNothing().when(tracker).postTraceStartMarker();
@@ -138,28 +143,30 @@
     public void testBeginCancel() {
         InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
 
-        ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+        ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
 
         Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
+        Configuration config = mock(Configuration.class);
+        when(config.isSurfaceOnly()).thenReturn(false);
         FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
                 new ThreadedRendererWrapper(mView.getThreadedRenderer()),
-                new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
-                mock(FrameTracker.ChoreographerWrapper.class),
-                new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
-                /*traceThresholdFrameTimeMillis=*/ -1, null));
+                new ViewRootWrapper(mView.getViewRootImpl()),
+                new SurfaceControlWrapper(), mock(FrameTracker.ChoreographerWrapper.class),
+                new FrameMetricsWrapper(),
+                /* traceThresholdMissedFrames= */ 1, /* traceThresholdFrameTimeMillis= */ -1,
+                /* FrameTrackerListener */ null, config));
         doReturn(tracker).when(monitor).createFrameTracker(any(), any());
         doNothing().when(tracker).triggerPerfetto();
         doNothing().when(tracker).postTraceStartMarker();
 
         assertThat(monitor.begin(mView, session.getCuj())).isTrue();
         verify(tracker).begin();
-        verify(mWorker.getThreadHandler(), atLeastOnce()).sendMessageAtTime(captor.capture(),
-                anyLong());
-        Runnable runnable = captor.getValue().getCallback();
+        verify(monitor).scheduleTimeoutAction(anyInt(), anyLong(), captor.capture());
+        Runnable runnable = captor.getValue();
         assertThat(runnable).isNotNull();
         mWorker.getThreadHandler().removeCallbacks(runnable);
         runnable.run();
-        verify(tracker).cancel(FrameTracker.REASON_CANCEL_NORMAL);
+        verify(tracker).cancel(FrameTracker.REASON_CANCEL_TIMEOUT);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 7a84201..cb6e88b 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -295,7 +295,6 @@
     }
 
     @SmallTest
-    @SkipPresubmit("b/180015146")
     public void testAlarmStartAndFinishLocked() throws Exception {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
@@ -333,7 +332,6 @@
     }
 
     @SmallTest
-    @SkipPresubmit("b/180015146")
     public void testAlarmStartAndFinishLocked_workSource() throws Exception {
         final MockClock clocks = new MockClock(); // holds realtime and uptime in ms
         MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index b59b84bb..63e13fd 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -186,7 +186,6 @@
         sPerProcStateTimesAvailable = fgCpuTimes != null;
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testCpuFreqTimes() throws Exception {
         if (!sCpuFreqTimesAvailable) {
@@ -215,7 +214,6 @@
         batteryOffScreenOn();
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testCpuFreqTimes_screenOff() throws Exception {
         if (!sCpuFreqTimesAvailable) {
@@ -278,7 +276,6 @@
         batteryOffScreenOn();
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testCpuFreqTimes_stateTop() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -312,7 +309,6 @@
         batteryOffScreenOn();
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testIsolatedCpuFreqTimes_stateService() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -354,7 +350,6 @@
         batteryOffScreenOn();
     }
 
-    @SkipPresubmit("b/185960974 flaky")
     @Test
     public void testCpuFreqTimes_stateTopSleeping() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -389,7 +384,6 @@
     }
 
     @Test
-    @SkipPresubmit("b/183225190 flaky")
     public void testCpuFreqTimes_stateFgService() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
             Log.w(TAG, "Skipping " + testName.getMethodName()
@@ -455,7 +449,6 @@
         batteryOff();
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testCpuFreqTimes_stateBg() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
@@ -522,7 +515,6 @@
         batteryOffScreenOn();
     }
 
-    @SkipPresubmit("b/184201598 flaky")
     @Test
     public void testCpuFreqTimes_trackingDisabled() throws Exception {
         if (!sCpuFreqTimesAvailable || !sPerProcStateTimesAvailable) {
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
new file mode 100644
index 0000000..d800c2c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertFalse;
+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.nio.file.Files;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ProcLocksReaderTest {
+    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 testRunSimpleLocks() throws Exception {
+        String simpleLocks =
+                "1: POSIX  ADVISORY  READ  18403 fd:09:9070 1073741826 1073742335\n" +
+                "2: POSIX  ADVISORY  WRITE 18292 fd:09:34062 0 EOF\n";
+        assertFalse(runHasFileLocks(simpleLocks, 18402));
+        assertFalse(runHasFileLocks(simpleLocks, 18404));
+        assertTrue(runHasFileLocks(simpleLocks, 18403));
+        assertTrue(runHasFileLocks(simpleLocks, 18292));
+    }
+
+    @Test
+    public void testRunBlockedLocks() throws Exception {
+        String blockedLocks =
+                "1: POSIX  ADVISORY  READ  18403 fd:09:9070 1073741826 1073742335\n" +
+                "2: POSIX  ADVISORY  WRITE 18292 fd:09:34062 0 EOF\n" +
+                "2: -> POSIX  ADVISORY  WRITE 18291 fd:09:34062 0 EOF\n" +
+                "2: -> POSIX  ADVISORY  WRITE 18293 fd:09:34062 0 EOF\n" +
+                "3: POSIX  ADVISORY  READ  3888 fd:09:13992 128 128\n" +
+                "4: POSIX  ADVISORY  READ  3888 fd:09:14230 1073741826 1073742335\n";
+        assertFalse(runHasFileLocks(blockedLocks, 18402));
+        assertFalse(runHasFileLocks(blockedLocks, 18404));
+        assertTrue(runHasFileLocks(blockedLocks, 18403));
+        assertTrue(runHasFileLocks(blockedLocks, 18292));
+
+        assertFalse(runHasFileLocks(blockedLocks, 18291));
+        assertFalse(runHasFileLocks(blockedLocks, 18293));
+        assertTrue(runHasFileLocks(blockedLocks, 3888));
+    }
+
+    private boolean runHasFileLocks(String fileContents, int pid) throws Exception {
+        File tempFile = File.createTempFile("locks", null, mProcDirectory);
+        Files.write(tempFile.toPath(), fileContents.getBytes());
+        boolean result = new ProcLocksReader(tempFile.toString()).hasFileLocks(pid);
+        Files.delete(tempFile.toPath());
+        return result;
+    }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 269d842..516a5d2 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -299,7 +299,7 @@
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */,
                     null /* fixedRotationAdjustments */, null /* shareableActivityToken */,
-                    false /* launchedFromBubble */);
+                    false /* launchedFromBubble */, null /* taskfragmentToken */);
         }
 
         @Override
diff --git a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
index b6da195..0532628 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
@@ -166,6 +166,46 @@
         assertEquals(-1L, reader.nextOptionalLong(-1L));
     }
 
+    public void testInvalidLongs() throws Exception {
+        final ProcFileReader reader = buildReader("12: 34\n56 78@#\n");
+
+        assertEquals(12L, reader.nextLong(true));
+        assertEquals(34L, reader.nextLong(true));
+        reader.finishLine();
+        assertTrue(reader.hasMoreData());
+
+        assertEquals(56L, reader.nextLong(true));
+        assertEquals(78L, reader.nextLong(true));
+        reader.finishLine();
+        assertFalse(reader.hasMoreData());
+    }
+
+    public void testConsecutiveDelimiters() throws Exception {
+        final ProcFileReader reader = buildReader("1 2  3   4     5\n");
+
+        assertEquals(1L, reader.nextLong());
+        assertEquals(2L, reader.nextLong());
+        assertEquals(3L, reader.nextLong());
+        assertEquals(4L, reader.nextLong());
+        assertEquals(5L, reader.nextLong());
+        reader.finishLine();
+        assertFalse(reader.hasMoreData());
+    }
+
+    public void testIgnore() throws Exception {
+        final ProcFileReader reader = buildReader("a b c\n");
+
+        assertEquals("a", reader.nextString());
+        assertTrue(reader.hasMoreData());
+
+        reader.nextIgnored();
+        assertTrue(reader.hasMoreData());
+
+        assertEquals("c", reader.nextString());
+        reader.finishLine();
+        assertFalse(reader.hasMoreData());
+    }
+
     private static ProcFileReader buildReader(String string) throws IOException {
         return buildReader(string, 2048);
     }
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/BinderIdentityChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/BinderIdentityChecker.java
index 68477ed..00cd18c 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/BinderIdentityChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/BinderIdentityChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.contains;
 import static com.google.errorprone.matchers.Matchers.methodInvocation;
@@ -52,6 +53,7 @@
 @BugPattern(
     name = "AndroidFrameworkBinderIdentity",
     summary = "Verifies that Binder.clearCallingIdentity() is always restored",
+    linkType = NONE,
     severity = WARNING)
 public final class BinderIdentityChecker extends BugChecker implements MethodInvocationTreeMatcher {
     private static final Matcher<ExpressionTree> CLEAR_CALL = methodInvocation(staticMethod()
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
index 9d1cf87..4bee99e 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/BluetoothPermissionChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.bugpatterns.android.RequiresPermissionChecker.simpleNameMatches;
 import static com.google.errorprone.matchers.Matchers.allOf;
@@ -60,6 +61,7 @@
 @BugPattern(
     name = "AndroidFrameworkBluetoothPermission",
     summary = "Verifies that all Bluetooth APIs have consistent permissions",
+    linkType = NONE,
     severity = WARNING)
 public final class BluetoothPermissionChecker extends BugChecker implements MethodTreeMatcher {
     private static final Matcher<MethodTree> BLUETOOTH_API = allOf(
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/ClientSidePermissionCheckChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/ClientSidePermissionCheckChecker.java
index 8651a1a..d27e7a1 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/ClientSidePermissionCheckChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/ClientSidePermissionCheckChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.anyOf;
 import static com.google.errorprone.matchers.Matchers.enclosingClass;
@@ -42,6 +43,7 @@
 @BugPattern(
         name = "AndroidFrameworkClientSidePermissionCheck",
         summary = "Verifies that permission checks aren't done in the app's process",
+        linkType = NONE,
         severity = WARNING)
 public final class ClientSidePermissionCheckChecker
         extends BugChecker implements MethodInvocationTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
index e759663..43abc8b 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/CompatChangeChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.bugpatterns.android.TargetSdkChecker.binaryTreeExact;
 import static com.google.errorprone.matchers.Matchers.allOf;
@@ -51,6 +52,7 @@
 @BugPattern(
     name = "AndroidFrameworkCompatChange",
     summary = "Verifies that behavior changes use the modern compatibility framework",
+    linkType = NONE,
     severity = WARNING)
 public final class CompatChangeChecker extends BugChecker implements BinaryTreeMatcher {
     private static final Matcher<ExpressionTree> VERSION_CODE =
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
index 3a1bc1e..c1a2048 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/ContextUserIdChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.bugpatterns.android.UidChecker.getFlavor;
 import static com.google.errorprone.matchers.Matchers.anyOf;
@@ -54,6 +55,7 @@
 @BugPattern(
     name = "AndroidFrameworkContextUserId",
     summary = "Verifies that system_server calls use Context.getUserId()",
+    linkType = NONE,
     severity = WARNING)
 public final class ContextUserIdChecker extends BugChecker implements MethodInvocationTreeMatcher {
     private static final Matcher<Tree> INSIDE_MANAGER =
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientCollectionsChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientCollectionsChecker.java
index c4c1ab6..209dafaa 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientCollectionsChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientCollectionsChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
 
@@ -43,6 +44,7 @@
 @BugPattern(
     name = "AndroidFrameworkEfficientCollections",
     summary = "Verifies efficient collections best-practices",
+    linkType = NONE,
     severity = WARNING)
 public final class EfficientCollectionsChecker extends BugChecker implements NewClassTreeMatcher {
     private static final Matcher<Tree> IS_LIST = isSubtypeOf("java.util.List");
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
index c29a095..cae5d8e 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientParcelableChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.allOf;
 import static com.google.errorprone.matchers.Matchers.enclosingClass;
@@ -45,6 +46,7 @@
 @BugPattern(
     name = "AndroidFrameworkEfficientParcelable",
     summary = "Verifies Parcelable performance best-practices",
+    linkType = NONE,
     severity = WARNING)
 public final class EfficientParcelableChecker extends BugChecker
         implements MethodInvocationTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientStringsChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientStringsChecker.java
index 3a0fbd3..5c60d77 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientStringsChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientStringsChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.allOf;
 import static com.google.errorprone.matchers.Matchers.anyOf;
@@ -63,6 +64,7 @@
 @BugPattern(
     name = "AndroidFrameworkEfficientStrings",
     summary = "Verifies efficient Strings best-practices",
+    linkType = NONE,
     severity = WARNING)
 public final class EfficientStringsChecker extends BugChecker
         implements MethodInvocationTreeMatcher, NewClassTreeMatcher, CompoundAssignmentTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java
index b5f26e7..8706a68 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/EfficientXmlChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.anyOf;
 import static com.google.errorprone.matchers.Matchers.instanceMethod;
@@ -61,6 +62,7 @@
 @BugPattern(
     name = "AndroidFrameworkEfficientXml",
     summary = "Verifies efficient XML best-practices",
+    linkType = NONE,
     severity = WARNING)
 public final class EfficientXmlChecker extends BugChecker
         implements MethodInvocationTreeMatcher, NewClassTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
index e323a89..c1e0821 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.anyOf;
 import static com.google.errorprone.matchers.Matchers.contains;
@@ -45,6 +46,7 @@
 @BugPattern(
         name = "AndroidFrameworkPendingIntentMutability",
         summary = "Verifies that FLAG_MUTABLE or FLAG_IMMUTABLE is always set",
+        linkType = NONE,
         severity = WARNING)
 public final class PendingIntentMutabilityChecker extends BugChecker
         implements MethodInvocationTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
index d1e4309..9a41cb4 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.allOf;
 import static com.google.errorprone.matchers.Matchers.anyOf;
@@ -79,6 +80,7 @@
 @BugPattern(
     name = "AndroidFrameworkRequiresPermission",
     summary = "Verifies that @RequiresPermission annotations are consistent across AIDL",
+    linkType = NONE,
     severity = WARNING)
 public final class RequiresPermissionChecker extends BugChecker
         implements MethodTreeMatcher, MethodInvocationTreeMatcher {
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
index 130b256..f8b401b 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RethrowFromSystemChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.allOf;
 import static com.google.errorprone.matchers.Matchers.contains;
@@ -60,6 +61,7 @@
 @BugPattern(
     name = "AndroidFrameworkRethrowFromSystem",
     summary = "Verifies that system_server calls use rethrowFromSystemServer()",
+    linkType = NONE,
     severity = WARNING)
 public final class RethrowFromSystemChecker extends BugChecker implements TryTreeMatcher {
     private static final Matcher<Tree> INSIDE_MANAGER =
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
index 032ae00..5581d99 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/TargetSdkChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 import static com.google.errorprone.matchers.Matchers.allOf;
 import static com.google.errorprone.matchers.Matchers.anyOf;
@@ -59,6 +60,7 @@
 @BugPattern(
     name = "AndroidFrameworkTargetSdk",
     summary = "Verifies that all target SDK comparisons are sane",
+    linkType = NONE,
     severity = WARNING)
 public final class TargetSdkChecker extends BugChecker implements BinaryTreeMatcher {
     private static final Matcher<ExpressionTree> VERSION_CODE = FieldMatchers
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
index a2ee065..a4ad069 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
@@ -16,6 +16,7 @@
 
 package com.google.errorprone.bugpatterns.android;
 
+import static com.google.errorprone.BugPattern.LinkType.NONE;
 import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
 
 import com.google.auto.service.AutoService;
@@ -46,6 +47,7 @@
 @BugPattern(
     name = "AndroidFrameworkUid",
     summary = "Verifies that PID, UID and user ID arguments aren't crossed",
+    linkType = NONE,
     severity = WARNING)
 public final class UidChecker extends BugChecker implements MethodInvocationTreeMatcher,
         NewClassTreeMatcher {
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 6c1c2ee..36215ec 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -33,7 +33,7 @@
     private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
     private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
     private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
-            int format);
+            int format, long transactionPtr);
     private static native void nativeFlushShadowQueue(long ptr);
     private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
                                                               long frameNumber);
@@ -92,9 +92,15 @@
      * @param width The new width for the buffer.
      * @param height The new height for the buffer.
      * @param format The new format for the buffer.
+     * @param t Adds destination frame changes to the passed in transaction.
      */
+    public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format,
+            SurfaceControl.Transaction t) {
+        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, t.mNativeObject);
+    }
+
     public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
-        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
+        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, 0);
     }
 
     /**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 51bf6d53..42e470b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -255,12 +255,6 @@
             | FILTER_BITMAP_FLAG;
 
     /**
-     * These flags are always set on a reset paint or a new paint instantiated using
-     * {@link #Paint()}.
-     */
-    private static final int DEFAULT_PAINT_FLAGS = ANTI_ALIAS_FLAG | DITHER_FLAG;
-
-    /**
      * Font hinter option that disables font hinting.
      *
      * @see #setHinting(int)
@@ -577,12 +571,12 @@
      * On devices running {@link Build.VERSION_CODES#Q} and above,
      * {@code FILTER_BITMAP_FLAG} is set by this constructor, and it can be
      * cleared with {@link #setFlags} or {@link #setFilterBitmap}.
-     * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG} and
-     * {@code DITHER_FLAG} are set by this constructor, and they can be cleared with
-     * {@link #setFlags} or {@link #setAntiAlias} and {@link #setDither}, respectively.</p>
+     * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG}
+     * is set by this constructor, and it can be cleared with {@link #setFlags} or
+     * {@link #setAntiAlias}.</p>
      */
     public Paint() {
-        this(DEFAULT_PAINT_FLAGS);
+        this(ANTI_ALIAS_FLAG);
     }
 
     /**
@@ -627,7 +621,7 @@
     /** Restores the paint to its default settings. */
     public void reset() {
         nReset(mNativePaint);
-        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | DEFAULT_PAINT_FLAGS);
+        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | ANTI_ALIAS_FLAG);
 
         // TODO: Turning off hinting has undesirable side effects, we need to
         //       revisit hinting once we add support for subpixel positioning
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 01fd231..5fd53ad 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -35,6 +35,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 
 /**
  * <p>RenderNode is used to build hardware accelerated rendering hierarchies. Each RenderNode
@@ -263,7 +264,6 @@
      * @hide
      */
     public interface PositionUpdateListener {
-
         /**
          * Called by native by a Rendering Worker thread to update window position
          *
@@ -272,6 +272,21 @@
         void positionChanged(long frameNumber, int left, int top, int right, int bottom);
 
         /**
+         * Called by JNI
+         *
+         * @hide */
+        static boolean callPositionChanged(WeakReference<PositionUpdateListener> weakListener,
+                long frameNumber, int left, int top, int right, int bottom) {
+            final PositionUpdateListener listener = weakListener.get();
+            if (listener != null) {
+                listener.positionChanged(frameNumber, left, top, right, bottom);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        /**
          * Call to apply a stretch effect to any child SurfaceControl layers
          *
          * TODO: Fold this into positionChanged & have HWUI do the ASurfaceControl calls?
@@ -286,6 +301,26 @@
                 float childRelativeTop, float childRelativeRight, float childRelativeBottom) { }
 
         /**
+         * Called by JNI
+         *
+         * @hide */
+        static boolean callApplyStretch(WeakReference<PositionUpdateListener> weakListener,
+                long frameNumber, float width, float height,
+                float vecX, float vecY,
+                float maxStretchX, float maxStretchY, float childRelativeLeft,
+                float childRelativeTop, float childRelativeRight, float childRelativeBottom) {
+            final PositionUpdateListener listener = weakListener.get();
+            if (listener != null) {
+                listener.applyStretch(frameNumber, width, height, vecX, vecY, maxStretchX,
+                        maxStretchY, childRelativeLeft, childRelativeTop, childRelativeRight,
+                        childRelativeBottom);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        /**
          * Called by native on RenderThread to notify that the view is no longer in the
          * draw tree. UI thread is blocked at this point.
          *
@@ -293,6 +328,21 @@
          */
         void positionLost(long frameNumber);
 
+        /**
+         * Called by JNI
+         *
+         * @hide */
+        static boolean callPositionLost(WeakReference<PositionUpdateListener> weakListener,
+                long frameNumber) {
+            final PositionUpdateListener listener = weakListener.get();
+            if (listener != null) {
+                listener.positionLost(frameNumber);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
     }
 
     private static final class CompositePositionUpdateListener implements PositionUpdateListener {
@@ -353,7 +403,7 @@
             comp = comp.with(listener);
         }
         mCompositePositionUpdateListener = comp;
-        nRequestPositionUpdates(mNativeRenderNode, comp);
+        nRequestPositionUpdates(mNativeRenderNode, new WeakReference<>(comp));
     }
 
     /**
@@ -368,7 +418,7 @@
         if (comp != null) {
             comp = comp.without(listener);
             mCompositePositionUpdateListener = comp;
-            nRequestPositionUpdates(mNativeRenderNode, comp);
+            nRequestPositionUpdates(mNativeRenderNode, new WeakReference<>(comp));
         }
     }
 
@@ -1575,7 +1625,7 @@
     private static native int nGetAllocatedSize(long renderNode);
 
     private static native void nRequestPositionUpdates(long renderNode,
-            PositionUpdateListener callback);
+            WeakReference<PositionUpdateListener> callback);
 
     // Animations
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index dd64327..82b3f68 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -48,6 +48,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
 /**
@@ -494,7 +495,7 @@
 
         if (mAnimationCallbacks == null) {
             mAnimationCallbacks = new ArrayList<Animatable2.AnimationCallback>();
-            nSetOnAnimationEndListener(mState.mNativePtr, this);
+            nSetOnAnimationEndListener(mState.mNativePtr, new WeakReference<>(this));
         }
 
         if (!mAnimationCallbacks.contains(callback)) {
@@ -562,6 +563,13 @@
      *  callback, so no need to post.
      */
     @SuppressWarnings("unused")
+    private static void callOnAnimationEnd(WeakReference<AnimatedImageDrawable> weakDrawable) {
+        AnimatedImageDrawable drawable = weakDrawable.get();
+        if (drawable != null) {
+            drawable.onAnimationEnd();
+        }
+    }
+
     private void onAnimationEnd() {
         if (mAnimationCallbacks != null) {
             for (Animatable2.AnimationCallback callback : mAnimationCallbacks) {
@@ -603,7 +611,7 @@
     private static native void nSetRepeatCount(long nativePtr, int repeatCount);
     // Pass the drawable down to native so it can call onAnimationEnd.
     private static native void nSetOnAnimationEndListener(long nativePtr,
-            @Nullable AnimatedImageDrawable drawable);
+            @Nullable WeakReference<AnimatedImageDrawable> drawable);
     @FastNative
     private static native long nNativeByteSize(long nativePtr);
     @FastNative
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3616a4d..166a795 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -723,8 +723,17 @@
      */
     @Nullable
     public int[] getColors() {
-        return mGradientState.mGradientColors == null ?
-                null : mGradientState.mGradientColors.clone();
+        if (mGradientState.mGradientColors == null) {
+            return null;
+        } else {
+            int[] colors = new int[mGradientState.mGradientColors.length];
+            for (int i = 0; i < mGradientState.mGradientColors.length; i++) {
+                if (mGradientState.mGradientColors[i] != null) {
+                    colors[i] = mGradientState.mGradientColors[i].getDefaultColor();
+                }
+            }
+            return colors;
+        }
     }
 
     @Override
@@ -1277,7 +1286,15 @@
             mRect.set(bounds.left + inset, bounds.top + inset,
                       bounds.right - inset, bounds.bottom - inset);
 
-            final int[] gradientColors = st.mGradientColors;
+            int[] gradientColors = null;
+            if (st.mGradientColors != null) {
+                gradientColors = new int[st.mGradientColors.length];
+                for (int i = 0; i < gradientColors.length; i++) {
+                    if (st.mGradientColors[i] != null) {
+                        gradientColors[i] = st.mGradientColors[i].getDefaultColor();
+                    }
+                }
+            }
             if (gradientColors != null) {
                 final RectF r = mRect;
                 final float x0, x1, y0, y1;
@@ -1439,6 +1456,14 @@
             state.mStrokeColors = state.mStrokeColors.obtainForTheme(t);
         }
 
+        if (state.mGradientColors != null) {
+            for (int i = 0; i < state.mGradientColors.length; i++) {
+                if (state.mGradientColors[i] != null && state.mGradientColors[i].canApplyTheme()) {
+                    state.mGradientColors[i] = state.mGradientColors[i].obtainForTheme(t);
+                }
+            }
+        }
+
         applyThemeChildElements(t);
 
         updateLocalState(t.getResources());
@@ -1726,38 +1751,46 @@
         st.mGradient = a.getInt(
                 R.styleable.GradientDrawableGradient_type, st.mGradient);
 
+        ColorStateList startCSL = a.getColorStateList(
+                R.styleable.GradientDrawableGradient_startColor);
+        ColorStateList centerCSL = a.getColorStateList(
+                R.styleable.GradientDrawableGradient_centerColor);
+        ColorStateList endCSL = a.getColorStateList(
+                R.styleable.GradientDrawableGradient_endColor);
+
         final boolean hasGradientColors = st.mGradientColors != null;
         final boolean hasGradientCenter = st.hasCenterColor();
-        final int prevStart = hasGradientColors ? st.mGradientColors[0] : 0;
-        final int prevCenter = hasGradientCenter ? st.mGradientColors[1] : 0;
-        final int prevEnd;
 
-        if (st.hasCenterColor()) {
+        int startColor = startCSL != null ? startCSL.getDefaultColor() : 0;
+        int centerColor = centerCSL != null ? centerCSL.getDefaultColor() : 0;
+        int endColor = endCSL != null ? endCSL.getDefaultColor() : 0;
+
+        if (hasGradientColors && st.mGradientColors[0] != null) {
+            startColor = st.mGradientColors[0].getDefaultColor();
+        }
+        if (hasGradientCenter && st.mGradientColors[1] != null) {
+            centerColor = st.mGradientColors[1].getDefaultColor();
+        }
+        if (hasGradientCenter && st.mGradientColors[2] != null) {
             // if there is a center color, the end color is the last of the 3 values
-            prevEnd = st.mGradientColors[2];
-        } else if (hasGradientColors) {
+            endColor = st.mGradientColors[2].getDefaultColor();
+        } else if (hasGradientColors && st.mGradientColors[1] != null) {
             // if there is not a center color but there are already colors configured, then
             // the end color is the 2nd value in the array
-            prevEnd = st.mGradientColors[1];
-        } else {
-            // otherwise, there isn't a previously configured end color
-            prevEnd = 0;
+            endColor = st.mGradientColors[1].getDefaultColor();
         }
 
-        final int startColor = a.getColor(
-                R.styleable.GradientDrawableGradient_startColor, prevStart);
         final boolean hasCenterColor = a.hasValue(
                 R.styleable.GradientDrawableGradient_centerColor) || hasGradientCenter;
-        final int centerColor = a.getColor(
-                R.styleable.GradientDrawableGradient_centerColor, prevCenter);
-        final int endColor = a.getColor(
-                R.styleable.GradientDrawableGradient_endColor, prevEnd);
 
         if (hasCenterColor) {
-            st.mGradientColors = new int[3];
-            st.mGradientColors[0] = startColor;
-            st.mGradientColors[1] = centerColor;
-            st.mGradientColors[2] = endColor;
+            st.mGradientColors = new ColorStateList[3];
+            st.mGradientColors[0] =
+                    startCSL != null ? startCSL : ColorStateList.valueOf(startColor);
+            st.mGradientColors[1] =
+                    centerCSL != null ? centerCSL : ColorStateList.valueOf(centerColor);
+            st.mGradientColors[2] =
+                    endCSL != null ? endCSL : ColorStateList.valueOf(endColor);
 
             st.mPositions = new float[3];
             st.mPositions[0] = 0.0f;
@@ -1765,9 +1798,11 @@
             st.mPositions[1] = st.mCenterX != 0.5f ? st.mCenterX : st.mCenterY;
             st.mPositions[2] = 1f;
         } else {
-            st.mGradientColors = new int[2];
-            st.mGradientColors[0] = startColor;
-            st.mGradientColors[1] = endColor;
+            st.mGradientColors = new ColorStateList[2];
+            st.mGradientColors[0] =
+                    startCSL != null ? startCSL : ColorStateList.valueOf(startColor);
+            st.mGradientColors[1] =
+                    endCSL != null ? endCSL : ColorStateList.valueOf(endColor);
         }
 
         int angle = (int) a.getFloat(R.styleable.GradientDrawableGradient_angle, st.mAngle);
@@ -1981,7 +2016,7 @@
         public ColorStateList mSolidColors;
         public ColorStateList mStrokeColors;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug =  124050917)
-        public @ColorInt int[] mGradientColors;
+        public ColorStateList[] mGradientColors; // no support for state-based color
         public @ColorInt int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
         @UnsupportedAppUsage
@@ -2188,6 +2223,13 @@
 
         @Override
         public boolean canApplyTheme() {
+            boolean mGradientColorState = mGradientColors != null;
+            if (mGradientColors != null) {
+                for (int i = 0; i < mGradientColors.length; i++) {
+                    mGradientColorState |= (mGradientColors[i] != null && mGradientColors[i]
+                        .canApplyTheme());
+                }
+            }
             return mThemeAttrs != null
                     || mAttrSize != null || mAttrGradient != null
                     || mAttrSolid != null || mAttrStroke != null
@@ -2195,6 +2237,7 @@
                     || (mTint != null && mTint.canApplyTheme())
                     || (mStrokeColors != null && mStrokeColors.canApplyTheme())
                     || (mSolidColors != null && mSolidColors.canApplyTheme())
+                    || mGradientColorState
                     || super.canApplyTheme();
         }
 
@@ -2246,7 +2289,18 @@
         }
 
         public void setGradientColors(@Nullable int[] colors) {
-            mGradientColors = colors;
+            if (colors == null) {
+                mGradientColors = null;
+            } else {
+                // allocate new CSL array only if the size of the current array is different
+                // from the size of the given parameter
+                if (mGradientColors == null || mGradientColors.length != colors.length) {
+                    mGradientColors = new ColorStateList[colors.length];
+                }
+                for (int i = 0; i < colors.length; i++) {
+                    mGradientColors[i] = ColorStateList.valueOf(colors[i]);
+                }
+            }
             mSolidColors = null;
             computeOpacity();
         }
@@ -2263,7 +2317,8 @@
 
             if (mGradientColors != null) {
                 for (int i = 0; i < mGradientColors.length; i++) {
-                    if (!isOpaque(mGradientColors[i])) {
+                    if (mGradientColors[i] != null
+                            && !isOpaque(mGradientColors[i].getDefaultColor())) {
                         return;
                     }
                 }
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 74fb618..872331c 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -53,6 +53,7 @@
     private long mStartTime;
     private boolean mForceSoftware;
     private Animator mLoopAnimation;
+    private Animator mCurrentAnimation;
 
     RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
             boolean forceSoftware) {
@@ -66,7 +67,7 @@
 
     @NonNull RippleAnimationSession enter(Canvas canvas) {
         mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        if (isHwAccelerated(canvas)) {
+        if (useRTAnimations(canvas)) {
             enterHardware((RecordingCanvas) canvas);
         } else {
             enterSoftware();
@@ -74,8 +75,14 @@
         return this;
     }
 
+    void end() {
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.end();
+        }
+    }
+
     @NonNull RippleAnimationSession exit(Canvas canvas) {
-        if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas);
+        if (useRTAnimations(canvas)) exitHardware((RecordingCanvas) canvas);
         else exitSoftware();
         return this;
     }
@@ -95,8 +102,12 @@
         return this;
     }
 
-    private boolean isHwAccelerated(Canvas canvas) {
-        return canvas.isHardwareAccelerated() && !mForceSoftware;
+    private boolean useRTAnimations(Canvas canvas) {
+        if (mForceSoftware) return false;
+        if (!canvas.isHardwareAccelerated()) return false;
+        RecordingCanvas hwCanvas = (RecordingCanvas) canvas;
+        if (hwCanvas.mNode == null || !hwCanvas.mNode.isAttached()) return false;
+        return true;
     }
 
     private void exitSoftware() {
@@ -114,10 +125,12 @@
                 if (mLoopAnimation != null) mLoopAnimation.cancel();
                 Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                 if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
+                if (mCurrentAnimation == expand) mCurrentAnimation = null;
             }
         });
         expand.setInterpolator(LINEAR_INTERPOLATOR);
         expand.start();
+        mCurrentAnimation = expand;
     }
 
     private long computeDelay() {
@@ -147,6 +160,7 @@
                 if (mLoopAnimation != null) mLoopAnimation.cancel();
                 Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                 if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
+                if (mCurrentAnimation == exit) mCurrentAnimation = null;
             }
         });
         exit.setTarget(canvas);
@@ -155,6 +169,7 @@
         long delay = computeDelay();
         exit.setStartDelay(delay);
         exit.start();
+        mCurrentAnimation = exit;
     }
 
     private void enterHardware(RecordingCanvas canvas) {
@@ -167,6 +182,7 @@
                 mStartTime + MAX_NOISE_PHASE);
         loop.setTarget(canvas);
         startAnimation(expand, loop);
+        mCurrentAnimation = expand;
     }
 
     private void startAnimation(Animator expand, Animator loop) {
@@ -200,6 +216,7 @@
             mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
         });
         startAnimation(expand, loop);
+        mCurrentAnimation = expand;
     }
 
     void setRadius(float radius) {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index b994ad2..7354c90 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -49,7 +49,9 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.os.Build;
+import android.os.Looper;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
 
@@ -113,6 +115,7 @@
  * @attr ref android.R.styleable#RippleDrawable_color
  */
 public class RippleDrawable extends LayerDrawable {
+    private static final String TAG = "RippleDrawable";
     /**
      * Radius value that specifies the ripple radius should be computed based
      * on the size of the ripple's container.
@@ -278,6 +281,15 @@
         }
 
         cancelExitingRipples();
+        endPatternedAnimations();
+    }
+
+    private void endPatternedAnimations() {
+        for (int i = 0; i < mRunningAnimations.size(); i++) {
+            RippleAnimationSession session = mRunningAnimations.get(i);
+            session.end();
+        }
+        mRunningAnimations.clear();
     }
 
     private void cancelExitingRipples() {
@@ -291,7 +303,6 @@
             Arrays.fill(ripples, 0, count, null);
         }
         mExitingRipplesCount = 0;
-        mExitingAnimation = true;
         // Always draw an additional "clean" frame after canceling animations.
         invalidateSelf(false);
     }
@@ -714,7 +725,7 @@
         }
 
         cancelExitingRipples();
-        exitPatternedAnimation();
+        endPatternedAnimations();
     }
 
     @Override
@@ -840,6 +851,10 @@
 
     private void startBackgroundAnimation() {
         mRunBackgroundAnimation = false;
+        if (Looper.myLooper() == null) {
+            Log.w(TAG, "Thread doesn't have a looper. Skipping animation.");
+            return;
+        }
         mBackgroundAnimation = ValueAnimator.ofFloat(mBackgroundOpacity, mTargetBackgroundOpacity);
         mBackgroundAnimation.setInterpolator(LINEAR_INTERPOLATOR);
         mBackgroundAnimation.setDuration(BACKGROUND_OPACITY_DURATION);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 27bd53d..531df30 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -116,6 +116,9 @@
                 secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent,
                 activityOptions);
 
+        // Set adjacent to each other so that the containers below will be invisible.
+        wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken);
+
         applyTransaction(wct);
     }
 
@@ -126,6 +129,7 @@
      */
     void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
         resizeTaskFragment(wct, fragmentToken, new Rect());
+        wct.setAdjacentTaskFragments(fragmentToken, null);
     }
 
     /**
@@ -155,13 +159,22 @@
      * @param ownerToken The token of the activity that creates this task fragment. It does not
      *                   have to be a child of this task fragment, but must belong to the same task.
      */
+    void createTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
+            IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
+        final TaskFragmentCreationParams fragmentOptions =
+                createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
+        wct.createTaskFragment(fragmentOptions);
+    }
+
+    /**
+     * @param ownerToken The token of the activity that creates this task fragment. It does not
+     *                   have to be a child of this task fragment, but must belong to the same task.
+     */
     private void createTaskFragmentAndReparentActivity(
             WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
             @NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
-        final TaskFragmentCreationParams fragmentOptions =
-                createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
-        wct.createTaskFragment(fragmentOptions)
-                .reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
+        createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
+        wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
     }
 
     /**
@@ -172,11 +185,8 @@
             WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
             @NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
             @Nullable Bundle activityOptions) {
-        final TaskFragmentCreationParams fragmentOptions =
-                createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
-        wct.createTaskFragment(fragmentOptions)
-                .startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
-                        activityOptions);
+        createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
+        wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
     }
 
     TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 6f67881..802976f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -20,13 +20,18 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityClient;
+import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application.ActivityLifecycleCallbacks;
+import android.app.Instrumentation;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.window.TaskFragmentAppearedInfo;
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
@@ -40,6 +45,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * Main controller class that manages split states and presentation.
@@ -57,11 +63,14 @@
     private SplitOrganizerCallback mSplitOrganizerCallback;
 
     public SplitController() {
-        mPresenter = new SplitPresenter(ActivityThread.currentActivityThread().getExecutor(),
-                this);
+        mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
         // Register a callback to be notified about activities being created.
-        ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
+        activityThread.getApplication().registerActivityLifecycleCallbacks(
                 new LifecycleCallbacks());
+        // Intercept activity starts to route activities to new containers if necessary.
+        Instrumentation instrumentation = activityThread.getInstrumentation();
+        instrumentation.addMonitor(new ActivityStartMonitor());
     }
 
     public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
@@ -116,8 +125,10 @@
         }
 
         container.setInfo(taskFragmentInfo);
-        if (taskFragmentInfo.isEmpty()) {
-            cleanupContainer(container, true /* shouldFinishDependent */);
+        // Check if there are no running activities - consider the container empty if there are no
+        // non-finishing activities left.
+        if (!taskFragmentInfo.hasRunningActivity()) {
+            mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
             updateCallbackIfNecessary();
         }
     }
@@ -129,7 +140,7 @@
             return;
         }
 
-        cleanupContainer(container, true /* shouldFinishDependent */);
+        mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
         updateCallbackIfNecessary();
     }
 
@@ -147,12 +158,13 @@
      * Checks if the activity start should be routed to a particular container. It can create a new
      * container for the activity and a new split container if necessary.
      */
+    // TODO(b/190433398): Break down into smaller functions.
     void onActivityCreated(@NonNull Activity launchedActivity) {
         final ComponentName componentName = launchedActivity.getComponentName();
 
         final List<ExtensionSplitRule> splitRules = getSplitRules();
         final TaskFragmentContainer currentContainer = getContainerWithActivity(
-                launchedActivity.getActivityToken());
+                launchedActivity.getActivityToken(), launchedActivity);
 
         // Check if the activity is configured to always be expanded.
         if (shouldExpand(componentName, splitRules)) {
@@ -200,6 +212,18 @@
             return;
         }
 
+        // Check if the split is already set.
+        final TaskFragmentContainer activityBelowContainer = getContainerWithActivity(
+                activityBelow.getActivityToken());
+        if (currentContainer != null && activityBelowContainer != null) {
+            final SplitContainer existingSplit = getActiveSplitForContainers(currentContainer,
+                    activityBelowContainer);
+            if (existingSplit != null) {
+                // There is already an active split with the activity below.
+                return;
+            }
+        }
+
         final ExtensionSplitPairRule splitPairRule = getSplitRule(
                 activityBelow.getComponentName(), componentName, splitRules);
         if (splitPairRule == null) {
@@ -212,15 +236,49 @@
         updateCallbackIfNecessary();
     }
 
+    private void onActivityConfigurationChanged(@NonNull Activity activity) {
+        final TaskFragmentContainer currentContainer = getContainerWithActivity(
+                activity.getActivityToken());
+
+        if (currentContainer != null) {
+            // Changes to activities in controllers are handled in
+            // onTaskFragmentParentInfoChanged
+            return;
+        }
+
+        // Check if activity requires a placeholder
+        launchPlaceholderIfNecessary(activity);
+    }
+
     /**
      * Returns a container that this activity is registered with. An activity can only belong to one
      * container, or no container at all.
      */
     @Nullable
     TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+        return getContainerWithActivity(activityToken, null /* activityToAdd */);
+    }
+
+    /**
+     * This method can only be called from {@link #onActivityCreated(Activity)}, use
+     * {@link #getContainerWithActivity(IBinder) } otherwise.
+     *
+     * Returns a container that this activity is registered with. The activity could be created
+     * before the container appeared, adding the activity to the container if so.
+     */
+    @Nullable
+    private TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken,
+            Activity activityToAdd) {
+        final IBinder taskFragmentToken = ActivityThread.currentActivityThread().getActivityClient(
+                activityToken).mInitialTaskFragmentToken;
         for (TaskFragmentContainer container : mContainers) {
             if (container.hasActivity(activityToken)) {
                 return container;
+            } else if (container.getTaskFragmentToken().equals(taskFragmentToken)) {
+                if (activityToAdd != null) {
+                    container.addPendingAppearedActivity(activityToAdd);
+                }
+                return container;
             }
         }
 
@@ -249,13 +307,10 @@
         mSplitContainers.add(splitContainer);
     }
 
-    void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
-        if (container.isFinished()) {
-            return;
-        }
-
-        container.finish(shouldFinishDependent);
-
+    /**
+     * Removes the container from bookkeeping records.
+     */
+    void removeContainer(@NonNull TaskFragmentContainer container) {
         // Remove all split containers that included this one
         mContainers.remove(container);
         List<SplitContainer> containersToRemove = new ArrayList<>();
@@ -266,8 +321,6 @@
             }
         }
         mSplitContainers.removeAll(containersToRemove);
-
-        mPresenter.deleteContainer(container);
     }
 
     /**
@@ -323,7 +376,7 @@
     }
 
     /**
-     * Returns the top active split container that has the provided container.
+     * Returns the top active split container that has the provided container, if available.
      */
     @Nullable
     private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) {
@@ -338,6 +391,26 @@
     }
 
     /**
+     * Returns the active split that has the provided containers as primary and secondary or as
+     * secondary and primary, if available.
+     */
+    @Nullable
+    private SplitContainer getActiveSplitForContainers(
+            @NonNull TaskFragmentContainer firstContainer,
+            @NonNull TaskFragmentContainer secondContainer) {
+        for (int i = mSplitContainers.size() - 1; i >= 0; i--) {
+            SplitContainer splitContainer = mSplitContainers.get(i);
+            final TaskFragmentContainer primary = splitContainer.getPrimaryContainer();
+            final TaskFragmentContainer secondary = splitContainer.getSecondaryContainer();
+            if ((firstContainer == secondary && secondContainer == primary)
+                    || (firstContainer == primary && secondContainer == secondary)) {
+                return splitContainer;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Checks if the container requires a placeholder and launches it if necessary.
      */
     private boolean launchPlaceholderIfNecessary(@NonNull TaskFragmentContainer container) {
@@ -384,7 +457,7 @@
             return false;
         }
 
-        cleanupContainer(splitContainer.getSecondaryContainer(),
+        mPresenter.cleanupContainer(splitContainer.getSecondaryContainer(),
                 false /* shouldFinishDependent */);
         return true;
     }
@@ -545,6 +618,10 @@
 
         @Override
         public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+        }
+
+        @Override
+        public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
             // Calling after Activity#onCreate is complete to allow the app launch something
             // first. In case of a configured placeholder activity we want to make sure
             // that we don't launch it if an activity itself already requested something to be
@@ -575,5 +652,56 @@
         @Override
         public void onActivityDestroyed(Activity activity) {
         }
+
+        @Override
+        public void onActivityConfigurationChanged(Activity activity) {
+            SplitController.this.onActivityConfigurationChanged(activity);
+        }
+    }
+
+    /** Executor that posts on the main application thread. */
+    private static class MainThreadExecutor implements Executor {
+        private final Handler handler = new Handler(Looper.getMainLooper());
+
+        @Override
+        public void execute(Runnable r) {
+            handler.post(r);
+        }
+    }
+
+    /**
+     * A monitor that intercepts all activity start requests originating in the client process and
+     * can amend them to target a specific task fragment to form a split.
+     */
+    private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
+
+        @Override
+        public Instrumentation.ActivityResult onStartActivity(Context who, Intent intent,
+                Bundle options) {
+            // TODO(b/190433398): Check if the activity is configured to always be expanded.
+
+            // Check if activity should be put in a split with the activity that launched it.
+            if (!(who instanceof Activity)) {
+                return super.onStartActivity(who, intent, options);
+            }
+            final Activity launchingActivity = (Activity) who;
+
+            final ExtensionSplitPairRule splitPairRule = getSplitRule(
+                    launchingActivity.getComponentName(), intent.getComponent(), getSplitRules());
+            if (splitPairRule == null) {
+                return super.onStartActivity(who, intent, options);
+            }
+
+            // Create a new split with an empty side container
+            final TaskFragmentContainer secondaryContainer = mPresenter
+                    .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+
+            // Amend the request to let the WM know that the activity should be placed in the
+            // dedicated container.
+            options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+                    secondaryContainer.getTaskFragmentToken());
+
+            return super.onStartActivity(who, intent, options);
+        }
     }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
index 90af72b..0f35629 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -68,11 +68,13 @@
     }
 
     /**
-     * Deletes the provided container and updates the presentation if necessary.
+     * Deletes the specified container and all other associated and dependent containers in the same
+     * transaction.
      */
-    void deleteContainer(TaskFragmentContainer container) {
+    void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        deleteTaskFragment(wct, container.getTaskFragmentToken());
+
+        container.finish(shouldFinishDependent, this, wct, mController);
 
         final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer();
         if (newTopContainer != null) {
@@ -83,6 +85,37 @@
     }
 
     /**
+     * Creates a new split with the primary activity and an empty secondary container.
+     * @return The newly created secondary container.
+     */
+    TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
+            @NonNull ExtensionSplitPairRule rule) {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+        final Rect parentBounds = getParentContainerBounds(primaryActivity);
+        final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+        final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
+                primaryActivity, primaryRectBounds, null);
+
+        // Create new empty task fragment
+        TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+        createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
+                primaryActivity.getActivityToken(), secondaryRectBounds,
+                WINDOWING_MODE_MULTI_WINDOW);
+        secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
+
+        // Set adjacent to each other so that the containers below will be invisible.
+        wct.setAdjacentTaskFragments(
+                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
+        applyTransaction(wct);
+
+        mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+
+        return secondaryContainer;
+    }
+
+    /**
      * Creates a new split container with the two provided activities.
      * @param primaryActivity An activity that should be in the primary container. If it is not
      *                        currently in an existing container, a new one will be created and the
@@ -99,57 +132,54 @@
 
         final Rect parentBounds = getParentContainerBounds(primaryActivity);
         final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
-        TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
-                primaryActivity.getActivityToken());
-        if (primaryContainer == null) {
-            primaryContainer = mController.newContainer(primaryActivity);
-
-            final TaskFragmentCreationParams fragmentOptions =
-                    createFragmentOptions(
-                            primaryContainer.getTaskFragmentToken(),
-                            primaryActivity.getActivityToken(),
-                            primaryRectBounds,
-                            WINDOWING_MODE_MULTI_WINDOW);
-            wct.createTaskFragment(fragmentOptions);
-
-            wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
-                    primaryActivity.getActivityToken());
-
-            primaryContainer.setLastRequestedBounds(primaryRectBounds);
-        } else {
-            resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
-        }
+        final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
+                primaryActivity, primaryRectBounds, null);
 
         final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
-        TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
-                secondaryActivity.getActivityToken());
-        if (secondaryContainer == null || secondaryContainer == primaryContainer) {
-            secondaryContainer = mController.newContainer(secondaryActivity);
+        final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
+                secondaryActivity, secondaryRectBounds, primaryContainer);
 
-            final TaskFragmentCreationParams fragmentOptions =
-                    createFragmentOptions(
-                            secondaryContainer.getTaskFragmentToken(),
-                            secondaryActivity.getActivityToken(),
-                            secondaryRectBounds,
-                            WINDOWING_MODE_MULTI_WINDOW);
-            wct.createTaskFragment(fragmentOptions);
-
-            wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
-                    secondaryActivity.getActivityToken());
-
-            secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
-        } else {
-            resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
-        }
-
-        // TODO(b/190433398): The primary container and the secondary container should also be set
-        // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
+        // Set adjacent to each other so that the containers below will be invisible.
+        wct.setAdjacentTaskFragments(
+                primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
         applyTransaction(wct);
 
         mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
     }
 
     /**
+     * Creates a new container or resizes an existing container for activity to the provided bounds.
+     * @param activity The activity to be re-parented to the container if necessary.
+     * @param containerToAvoid Re-parent from this container if an activity is already in it.
+     */
+    private TaskFragmentContainer prepareContainerForActivity(
+            @NonNull WindowContainerTransaction wct, @NonNull Activity activity,
+            @NonNull Rect bounds, @Nullable TaskFragmentContainer containerToAvoid) {
+        TaskFragmentContainer container = mController.getContainerWithActivity(
+                activity.getActivityToken());
+        if (container == null || container == containerToAvoid) {
+            container = mController.newContainer(activity);
+
+            final TaskFragmentCreationParams fragmentOptions =
+                    createFragmentOptions(
+                            container.getTaskFragmentToken(),
+                            activity.getActivityToken(),
+                            bounds,
+                            WINDOWING_MODE_MULTI_WINDOW);
+            wct.createTaskFragment(fragmentOptions);
+
+            wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
+                    activity.getActivityToken());
+
+            container.setLastRequestedBounds(bounds);
+        } else {
+            resizeTaskFragmentIfRegistered(wct, container, bounds);
+        }
+
+        return container;
+    }
+
+    /**
      * Starts a new activity to the side, creating a new split container. A new container will be
      * created for the activity that will be started.
      * @param launchingActivity An activity that should be in the primary container. If it is not
@@ -184,9 +214,6 @@
         primaryContainer.setLastRequestedBounds(primaryRectBounds);
         secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
 
-        // TODO(b/190433398): The primary container and the secondary container should also be set
-        // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
-
         mController.registerSplit(primaryContainer, launchingActivity, secondaryContainer,
                 rule);
     }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
index 368adef..a4f5c75 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -24,6 +24,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.window.TaskFragmentInfo;
+import android.window.WindowContainerTransaction;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,10 +46,10 @@
     private TaskFragmentInfo mInfo;
 
     /**
-     * Activity that is being reparented to this container, but haven't been added to {@link #mInfo}
-     * yet.
+     * Activities that are being reparented or being started to this container, but haven't been
+     * added to {@link #mInfo} yet.
      */
-    private Activity mReparentingActivity;
+    private final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
 
     /** Containers that are dependent on this one and should be completely destroyed on exit. */
     private final List<TaskFragmentContainer> mContainersToFinishOnExit =
@@ -71,7 +72,9 @@
      */
     TaskFragmentContainer(@Nullable Activity activity) {
         mToken = new Binder("TaskFragmentContainer");
-        mReparentingActivity = activity;
+        if (activity != null) {
+            addPendingAppearedActivity(activity);
+        }
     }
 
     /**
@@ -89,8 +92,8 @@
         // fragment info update with it placed in this container. We still want to apply rules
         // in this intermediate state.
         List<Activity> allActivities = new ArrayList<>();
-        if (mReparentingActivity != null) {
-            allActivities.add(mReparentingActivity);
+        if (!mPendingAppearedActivities.isEmpty()) {
+            allActivities.addAll(mPendingAppearedActivities);
         }
         // Add activities reported from the server.
         if (mInfo == null) {
@@ -106,12 +109,20 @@
         return allActivities;
     }
 
+    void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+        mPendingAppearedActivities.add(pendingAppearedActivity);
+    }
+
     boolean hasActivity(@NonNull IBinder token) {
         if (mInfo != null && mInfo.getActivities().contains(token)) {
             return true;
         }
-        return mReparentingActivity != null
-                && mReparentingActivity.getActivityToken().equals(token);
+        for (Activity activity : mPendingAppearedActivities) {
+            if (activity.getActivityToken().equals(token)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Nullable
@@ -121,14 +132,15 @@
 
     void setInfo(@Nullable TaskFragmentInfo info) {
         mInfo = info;
-        if (mInfo == null || mReparentingActivity == null) {
+        if (mInfo == null || mPendingAppearedActivities.isEmpty()) {
             return;
         }
         // Cleanup activities that were being re-parented
-        for (IBinder activityToken : mInfo.getActivities()) {
-            if (mReparentingActivity.getActivityToken().equals(activityToken)) {
-                mReparentingActivity = null;
-                break;
+        List<IBinder> infoActivities = mInfo.getActivities();
+        for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
+            final Activity activity = mPendingAppearedActivities.get(i);
+            if (infoActivities.contains(activity.getActivityToken())) {
+                mPendingAppearedActivities.remove(i);
             }
         }
     }
@@ -147,7 +159,7 @@
     }
 
     boolean isEmpty() {
-        return mReparentingActivity == null && (mInfo == null || mInfo.isEmpty());
+        return mPendingAppearedActivities.isEmpty() && (mInfo == null || mInfo.isEmpty());
     }
 
     /**
@@ -168,7 +180,8 @@
      * Removes all activities that belong to this process and finishes other containers/activities
      * configured to finish together.
      */
-    void finish(boolean shouldFinishDependent) {
+    void finish(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
+            @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
         if (mIsFinished) {
             return;
         }
@@ -179,13 +192,19 @@
             activity.finish();
         }
 
+        // Cleanup the visuals
+        presenter.deleteTaskFragment(wct, getTaskFragmentToken());
+        // Cleanup the records
+        controller.removeContainer(this);
+
         if (!shouldFinishDependent) {
             return;
         }
 
         // Finish dependent containers
         for (TaskFragmentContainer container : mContainersToFinishOnExit) {
-            container.finish(true /* shouldFinishDependent */);
+            container.finish(true /* shouldFinishDependent */, presenter,
+                    wct, controller);
         }
         mContainersToFinishOnExit.clear();
 
@@ -196,10 +215,10 @@
         mActivitiesToFinishOnExit.clear();
 
         // Finish activities that were being re-parented to this container.
-        if (mReparentingActivity != null) {
-            mReparentingActivity.finish();
-            mReparentingActivity = null;
+        for (Activity activity : mPendingAppearedActivities) {
+            activity.finish();
         }
+        mPendingAppearedActivities.clear();
     }
 
     boolean isFinished() {
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
index 8710fb8..96d2d7c 100644
--- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
@@ -18,7 +18,7 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
     <solid
-        android:color="@android:color/system_neutral1_900"
+        android:color="@android:color/system_neutral1_800"
         />
     <corners android:radius="20dp" />
 
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index c09ae53..7658fca 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -20,10 +20,10 @@
     android:id="@+id/settings_button"
     android:layout_gravity="start"
     android:layout_width="wrap_content"
-    android:layout_height="40dp"
-    android:layout_marginTop="8dp"
-    android:layout_marginLeft="16dp"
-    android:layout_marginBottom="8dp"
+    android:layout_height="@dimen/bubble_manage_button_height"
+    android:layout_marginStart="@dimen/bubble_manage_button_margin"
+    android:layout_marginTop="@dimen/bubble_manage_button_margin"
+    android:layout_marginBottom="@dimen/bubble_manage_button_margin"
     android:focusable="true"
     android:text="@string/manage_bubbles_text"
     android:textSize="@*android:dimen/text_size_body_2_material"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index f4b3aca..298ad30 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -25,15 +25,15 @@
         android:id="@+id/bubble_manage_menu_dismiss_container"
         android:background="@drawable/bubble_manage_menu_row"
         android:layout_width="match_parent"
-        android:layout_height="48dp"
+        android:layout_height="@dimen/bubble_menu_item_height"
         android:gravity="center_vertical"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingStart="@dimen/bubble_menu_padding"
+        android:paddingEnd="@dimen/bubble_menu_padding"
         android:orientation="horizontal">
 
         <ImageView
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="@dimen/bubble_menu_icon_size"
+            android:layout_height="@dimen/bubble_menu_icon_size"
             android:src="@drawable/ic_remove_no_shadow"
             android:tint="@color/bubbles_icon_tint"/>
 
@@ -50,15 +50,15 @@
         android:id="@+id/bubble_manage_menu_dont_bubble_container"
         android:background="@drawable/bubble_manage_menu_row"
         android:layout_width="match_parent"
-        android:layout_height="48dp"
+        android:layout_height="@dimen/bubble_menu_item_height"
         android:gravity="center_vertical"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingStart="@dimen/bubble_menu_padding"
+        android:paddingEnd="@dimen/bubble_menu_padding"
         android:orientation="horizontal">
 
         <ImageView
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="@dimen/bubble_menu_icon_size"
+            android:layout_height="@dimen/bubble_menu_icon_size"
             android:src="@drawable/bubble_ic_stop_bubble"
             android:tint="@color/bubbles_icon_tint"/>
 
@@ -75,16 +75,16 @@
         android:id="@+id/bubble_manage_menu_settings_container"
         android:background="@drawable/bubble_manage_menu_row"
         android:layout_width="match_parent"
-        android:layout_height="48dp"
+        android:layout_height="@dimen/bubble_menu_item_height"
         android:gravity="center_vertical"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingStart="@dimen/bubble_menu_padding"
+        android:paddingEnd="@dimen/bubble_menu_padding"
         android:orientation="horizontal">
 
         <ImageView
             android:id="@+id/bubble_manage_menu_settings_icon"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="@dimen/bubble_menu_icon_size"
+            android:layout_height="@dimen/bubble_menu_icon_size"
             android:src="@drawable/ic_remove_no_shadow"/>
 
         <TextView
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 624b8b3..c2b6ffb 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -31,7 +31,7 @@
     <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్‌లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index f28ee82..7da31aa 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -100,6 +100,8 @@
     <dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
     <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
     <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
+    <!-- If the screen percentage is smaller than this, we'll use this value instead.  -->
+    <dimen name="bubbles_flyout_min_width_large_screen">200dp</dimen>
     <!-- Padding between status bar and bubbles when displayed in expanded state -->
     <dimen name="bubble_padding_top">16dp</dimen>
     <!-- Space between bubbles when expanded. -->
@@ -149,9 +151,17 @@
     <!-- Extra padding around the dismiss target for bubbles -->
     <dimen name="bubble_dismiss_slop">16dp</dimen>
     <!-- Height of button allowing users to adjust settings for bubbles. -->
-    <dimen name="bubble_manage_button_height">56dp</dimen>
+    <dimen name="bubble_manage_button_height">36dp</dimen>
+    <!-- Height of manage button including margins. -->
+    <dimen name="bubble_manage_button_total_height">68dp</dimen>
+    <!-- The margin around the outside of the manage button. -->
+    <dimen name="bubble_manage_button_margin">16dp</dimen>
     <!-- Height of an item in the bubble manage menu. -->
     <dimen name="bubble_menu_item_height">60dp</dimen>
+    <!-- Padding applied to the bubble manage menu. -->
+    <dimen name="bubble_menu_padding">16dp</dimen>
+    <!-- Size of the icons in the manage menu. -->
+    <dimen name="bubble_menu_icon_size">24dp</dimen>
     <!-- Max width of the message bubble-->
     <dimen name="bubble_message_max_width">144dp</dimen>
     <!-- Min width of the message bubble -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index d1fbf31..9bbede3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -24,6 +24,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -47,6 +48,7 @@
     private final Optional<AppPairsController> mAppPairsOptional;
     private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
     private final FullscreenTaskListener mFullscreenTaskListener;
+    private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
     private final ShellExecutor mMainExecutor;
     private final Transitions mTransitions;
     private final StartingWindowController mStartingWindow;
@@ -62,6 +64,7 @@
             Optional<AppPairsController> appPairsOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
             Transitions transitions,
             StartingWindowController startingWindow,
             ShellExecutor mainExecutor) {
@@ -74,6 +77,7 @@
         mAppPairsOptional = appPairsOptional;
         mFullscreenTaskListener = fullscreenTaskListener;
         mPipTouchHandlerOptional = pipTouchHandlerOptional;
+        mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
         mTransitions = transitions;
         mMainExecutor = mainExecutor;
         mStartingWindow = startingWindow;
@@ -108,6 +112,11 @@
         // controller instead of the feature interface, can just initialize the touch handler if
         // needed
         mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
+
+        // Initialize optional freeform
+        mFreeformTaskListenerOptional.ifPresent(f ->
+                mShellTaskOrganizer.addListenerForType(
+                        f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
     }
 
     @ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index ba0ab6d..ab8a21c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -71,12 +71,14 @@
     public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2;
     public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
     public static final int TASK_LISTENER_TYPE_PIP = -4;
+    public static final int TASK_LISTENER_TYPE_FREEFORM = -5;
 
     @IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
             TASK_LISTENER_TYPE_UNDEFINED,
             TASK_LISTENER_TYPE_FULLSCREEN,
             TASK_LISTENER_TYPE_MULTI_WINDOW,
             TASK_LISTENER_TYPE_PIP,
+            TASK_LISTENER_TYPE_FREEFORM,
     })
     public @interface TaskListenerType {}
 
@@ -572,6 +574,7 @@
             case WINDOWING_MODE_PINNED:
                 return TASK_LISTENER_TYPE_PIP;
             case WINDOWING_MODE_FREEFORM:
+                return TASK_LISTENER_TYPE_FREEFORM;
             case WINDOWING_MODE_UNDEFINED:
             default:
                 return TASK_LISTENER_TYPE_UNDEFINED;
@@ -586,6 +589,8 @@
                 return "TASK_LISTENER_TYPE_MULTI_WINDOW";
             case TASK_LISTENER_TYPE_PIP:
                 return "TASK_LISTENER_TYPE_PIP";
+            case TASK_LISTENER_TYPE_FREEFORM:
+                return "TASK_LISTENER_TYPE_FREEFORM";
             case TASK_LISTENER_TYPE_UNDEFINED:
                 return "TASK_LISTENER_TYPE_UNDEFINED";
             default:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 8aca01d..2aead93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -62,4 +62,10 @@
      */
     public static final Interpolator PANEL_CLOSE_ACCELERATED =
             new PathInterpolator(0.3f, 0, 0.5f, 1);
+
+    public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+    public static final PathInterpolator DIM_INTERPOLATOR =
+            new PathInterpolator(.23f, .87f, .52f, -0.11f);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 94a8758..8405385 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -215,7 +215,7 @@
 
             if (mSplitLayout != null) {
                 if (mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
-                    onBoundsChanged(mSplitLayout);
+                    onLayoutChanged(mSplitLayout);
                 }
                 // updateConfiguration re-inits the dividerbar, so show it now
                 mSyncQueue.runInSync(t -> t.show(mSplitLayout.getDividerLeash()));
@@ -299,17 +299,24 @@
     }
 
     @Override
-    public void onBoundsChanging(SplitLayout layout) {
+    public void onLayoutChanging(SplitLayout layout) {
         mSyncQueue.runInSync(t ->
                 layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
     }
 
     @Override
-    public void onBoundsChanged(SplitLayout layout) {
+    public void onLayoutChanged(SplitLayout layout) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
         mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t ->
                 layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
     }
+
+    @Override
+    public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
+        mController.getTaskOrganizer().applyTransaction(wct);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 28e2f7dd..e7764ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -56,7 +56,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -98,7 +97,6 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
 
@@ -581,7 +579,7 @@
 
     /**
      * BubbleStackView is lazily created by this method the first time a Bubble is added. This
-     * method initializes the stack view and adds it to the StatusBar just above the scrim.
+     * method initializes the stack view and adds it to window manager.
      */
     private void ensureStackViewCreated() {
         if (mStackView == null) {
@@ -629,7 +627,6 @@
         try {
             mAddedToWindowManager = true;
             mBubbleData.getOverflow().initialize(this);
-            mStackView.addView(mBubbleScrim);
             mWindowManager.addView(mStackView, mWmLayoutParams);
             // Position info is dependent on us being attached to a window
             mBubblePositioner.update();
@@ -661,7 +658,6 @@
             mAddedToWindowManager = false;
             if (mStackView != null) {
                 mWindowManager.removeView(mStackView);
-                mStackView.removeView(mBubbleScrim);
                 mBubbleData.getOverflow().cleanUpExpandedState();
             } else {
                 Log.w(TAG, "StackView added to WindowManager, but was null when removing!");
@@ -763,13 +759,6 @@
         }
     }
 
-    private void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
-        mBubbleScrim = view;
-        callback.accept(mMainExecutor, mMainExecutor.executeBlockingForResult(() -> {
-            return Looper.myLooper();
-        }, Looper.class));
-    }
-
     private void setSysuiProxy(Bubbles.SysuiProxy proxy) {
         mSysuiProxy = proxy;
     }
@@ -1574,13 +1563,6 @@
         }
 
         @Override
-        public void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback) {
-            mMainExecutor.execute(() -> {
-                BubbleController.this.setBubbleScrim(view, callback);
-            });
-        }
-
-        @Override
         public void setExpandListener(BubbleExpandListener listener) {
             mMainExecutor.execute(() -> {
                 BubbleController.this.setExpandListener(listener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index a02fa9b..252b588 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -735,6 +735,10 @@
         mManageButton.getBoundsOnScreen(rect);
     }
 
+    public int getManageButtonMargin() {
+        return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart();
+    }
+
     /**
      * Cleans up anything related to the task and {@code TaskView}. If this view should be reused
      * after this method is called, then
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 35a4f33..9374da4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -56,9 +56,6 @@
  * transform into the 'new' dot, which is used during flyout dismiss animations/gestures.
  */
 public class BubbleFlyoutView extends FrameLayout {
-    /** Max width of the flyout, in terms of percent of the screen width. */
-    private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f;
-
     /** Translation Y of fade animation. */
     private static final float FLYOUT_FADE_Y = 40f;
 
@@ -68,6 +65,8 @@
     // Whether the flyout view should show a pointer to the bubble.
     private static final boolean SHOW_POINTER = false;
 
+    private BubblePositioner mPositioner;
+
     private final int mFlyoutPadding;
     private final int mFlyoutSpaceFromBubble;
     private final int mPointerSize;
@@ -156,10 +155,11 @@
     /** Callback to run when the flyout is hidden. */
     @Nullable private Runnable mOnHide;
 
-    public BubbleFlyoutView(Context context) {
+    public BubbleFlyoutView(Context context, BubblePositioner positioner) {
         super(context);
-        LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
+        mPositioner = positioner;
 
+        LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
         mFlyoutTextContainer = findViewById(R.id.bubble_flyout_text_container);
         mSenderText = findViewById(R.id.bubble_flyout_name);
         mSenderAvatar = findViewById(R.id.bubble_flyout_avatar);
@@ -230,11 +230,11 @@
     /*
      * Fade animation for consecutive flyouts.
      */
-    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
+    void animateUpdate(Bubble.FlyoutMessage flyoutMessage, PointF stackPos,
             boolean hideDot, Runnable onHide) {
         mOnHide = onHide;
         final Runnable afterFadeOut = () -> {
-            updateFlyoutMessage(flyoutMessage, parentWidth);
+            updateFlyoutMessage(flyoutMessage);
             // Wait for TextViews to layout with updated height.
             post(() -> {
                 fade(true /* in */, stackPos, hideDot, () -> {} /* after */);
@@ -266,7 +266,7 @@
                 .withEndAction(afterFade);
     }
 
-    private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) {
+    private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage) {
         final Drawable senderAvatar = flyoutMessage.senderAvatar;
         if (senderAvatar != null && flyoutMessage.isGroupChat) {
             mSenderAvatar.setVisibility(VISIBLE);
@@ -278,8 +278,7 @@
             mSenderText.setTranslationX(0);
         }
 
-        final int maxTextViewWidth =
-                (int) (parentWidth * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2;
+        final int maxTextViewWidth = (int) mPositioner.getMaxFlyoutSize() - mFlyoutPadding * 2;
 
         // Name visibility
         if (!TextUtils.isEmpty(flyoutMessage.senderName)) {
@@ -328,22 +327,20 @@
     void setupFlyoutStartingAsDot(
             Bubble.FlyoutMessage flyoutMessage,
             PointF stackPos,
-            float parentWidth,
             boolean arrowPointingLeft,
             int dotColor,
             @Nullable Runnable onLayoutComplete,
             @Nullable Runnable onHide,
             float[] dotCenter,
-            boolean hideDot,
-            BubblePositioner positioner)  {
+            boolean hideDot)  {
 
-        mBubbleSize = positioner.getBubbleSize();
+        mBubbleSize = mPositioner.getBubbleSize();
 
         mOriginalDotSize = SIZE_PERCENTAGE * mBubbleSize;
         mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
         mNewDotSize = mNewDotRadius * 2f;
 
-        updateFlyoutMessage(flyoutMessage, parentWidth);
+        updateFlyoutMessage(flyoutMessage);
 
         mArrowPointingLeft = arrowPointingLeft;
         mDotColor = dotColor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 0a856a8..df804ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -61,10 +61,16 @@
     public static final int NUM_VISIBLE_WHEN_RESTING = 2;
     /** Indicates a bubble's height should be the maximum available space. **/
     public static final int MAX_HEIGHT = -1;
+    /** The max percent of screen width to use for the flyout on large screens. */
+    public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f;
+    /** The max percent of screen width to use for the flyout on phone. */
+    public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
+
 
     private Context mContext;
     private WindowManager mWindowManager;
     private Rect mPositionRect;
+    private Rect mScreenRect;
     private @Surface.Rotation int mRotation = Surface.ROTATION_0;
     private Insets mInsets;
     private int mDefaultMaxBubbles;
@@ -77,10 +83,10 @@
     private int mPointerMargin;
     private int mPointerWidth;
     private int mPointerHeight;
-    private int mPointerOverlap;
     private int mManageButtonHeight;
     private int mExpandedViewMinHeight;
     private int mOverflowHeight;
+    private int mMinimumFlyoutWidthLargeScreen;
 
     private PointF mPinLocation;
     private PointF mRestingStackPosition;
@@ -149,6 +155,7 @@
         mRotation = rotation;
         mInsets = insets;
 
+        mScreenRect = new Rect(bounds);
         mPositionRect = new Rect(bounds);
         mPositionRect.left += mInsets.left;
         mPositionRect.top += mInsets.top;
@@ -166,10 +173,11 @@
         mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
         mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
-        mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
-        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+        mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
         mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
         mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
+        mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize(
+                R.dimen.bubbles_flyout_min_width_large_screen);
 
         mMaxBubbles = calculateMaxBubbles();
 
@@ -426,6 +434,17 @@
     }
 
     /**
+     * @return the width of the bubble flyout (message originating from the bubble).
+     */
+    public float getMaxFlyoutSize() {
+        if (isLargeScreen()) {
+            return Math.max(mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN,
+                    mMinimumFlyoutWidthLargeScreen);
+        }
+        return mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT;
+    }
+
+    /**
      * Sets the stack's most recent position along the edge of the screen. This is saved when the
      * last bubble is removed, so that the stack can be restored in its previous position.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 36b8923..8f2df4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -19,6 +19,8 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -33,11 +35,11 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.Log;
@@ -106,9 +108,6 @@
      */
     private static final float FLYOUT_OVERSCROLL_ATTENUATION_FACTOR = 8f;
 
-    /** Duration of the flyout alpha animations. */
-    private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100;
-
     private static final int FADE_IN_DURATION = 320;
 
     /** Percent to darken the bubbles when they're in the dismiss target. */
@@ -122,6 +121,10 @@
 
     private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
 
+    private static final int MANAGE_MENU_SCRIM_ANIM_DURATION = 150;
+
+    private static final float SCRIM_ALPHA = 0.6f;
+
     /**
      * How long to wait to animate the stack temporarily invisible after a drag/flyout hide
      * animation ends, if we are in fact temporarily invisible.
@@ -195,7 +198,8 @@
     private StackAnimationController mStackAnimationController;
     private ExpandedAnimationController mExpandedAnimationController;
 
-    private View mTaskbarScrim;
+    private View mScrim;
+    private View mManageMenuScrim;
     private FrameLayout mExpandedViewContainer;
 
     /** Matrix used to scale the expanded view container with a given pivot point. */
@@ -858,11 +862,20 @@
             mBubbleData.setExpanded(true);
         });
 
-        mTaskbarScrim = new View(getContext());
-        mTaskbarScrim.setBackgroundColor(Color.BLACK);
-        addView(mTaskbarScrim);
-        mTaskbarScrim.setAlpha(0f);
-        mTaskbarScrim.setVisibility(GONE);
+        mScrim = new View(getContext());
+        mScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        mScrim.setBackgroundDrawable(new ColorDrawable(
+                getResources().getColor(android.R.color.system_neutral1_1000)));
+        addView(mScrim);
+        mScrim.setAlpha(0f);
+
+        mManageMenuScrim = new View(getContext());
+        mManageMenuScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+                getResources().getColor(android.R.color.system_neutral1_1000)));
+        addView(mManageMenuScrim, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        mManageMenuScrim.setAlpha(0f);
+        mManageMenuScrim.setVisibility(INVISIBLE);
 
         mOrientationChangedListener =
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
@@ -1173,7 +1186,7 @@
         if (mFlyout != null) {
             removeView(mFlyout);
         }
-        mFlyout = new BubbleFlyoutView(getContext());
+        mFlyout = new BubbleFlyoutView(getContext(), mPositioner);
         mFlyout.setVisibility(GONE);
         mFlyout.setOnClickListener(mFlyoutClickListener);
         mFlyout.setOnTouchListener(mFlyoutTouchListener);
@@ -1220,6 +1233,10 @@
         updateOverflow();
         updateUserEdu();
         updateExpandedViewTheme();
+        mScrim.setBackgroundDrawable(new ColorDrawable(
+                getResources().getColor(android.R.color.system_neutral1_1000)));
+        mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+                getResources().getColor(android.R.color.system_neutral1_1000)));
     }
 
     /**
@@ -1799,6 +1816,20 @@
         mExpandedViewAlphaAnimator.start();
     }
 
+    private void showScrim(boolean show) {
+        if (show) {
+            mScrim.animate()
+                    .setInterpolator(ALPHA_IN)
+                    .alpha(SCRIM_ALPHA)
+                    .start();
+        } else {
+            mScrim.animate()
+                    .alpha(0f)
+                    .setInterpolator(ALPHA_OUT)
+                    .start();
+        }
+    }
+
     private void animateExpansion() {
         cancelDelayedExpandCollapseSwitchAnimations();
         final boolean showVertically = mPositioner.showBubblesVertically();
@@ -1808,6 +1839,7 @@
         }
         beforeExpandedViewAnimation();
 
+        showScrim(true);
         updateZOrder();
         updateBadges(false /* setBadgeForCollapsedStack */);
         mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -1819,16 +1851,6 @@
             }
         } /* after */);
 
-        if (mPositioner.showingInTaskbar()
-                // Don't need the scrim when the bar is at the bottom
-                && mPositioner.getTaskbarPosition() != BubblePositioner.TASKBAR_POSITION_BOTTOM) {
-            mTaskbarScrim.getLayoutParams().width = mPositioner.getTaskbarSize();
-            mTaskbarScrim.setTranslationX(mStackOnLeftOrWillBe
-                    ? 0f
-                    : mPositioner.getAvailableRect().right - mPositioner.getTaskbarSize());
-            mTaskbarScrim.setVisibility(VISIBLE);
-            mTaskbarScrim.animate().alpha(1f).start();
-        }
         final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
                 getBubbleIndex(mExpandedBubble));
         mExpandedViewContainer.setTranslationX(0f);
@@ -1939,6 +1961,8 @@
         mIsExpanded = false;
         mIsExpansionAnimating = true;
 
+        showScrim(false);
+
         mBubbleContainer.cancelAllAnimations();
 
         // If we were in the middle of swapping, the animating-out surface would have been scaling
@@ -1956,10 +1980,6 @@
                 /* collapseTo */,
                 () -> mBubbleContainer.setActiveController(mStackAnimationController));
 
-        if (mTaskbarScrim.getVisibility() == VISIBLE) {
-            mTaskbarScrim.animate().alpha(0f).start();
-        }
-
         int index;
         if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
             index = mBubbleData.getBubbles().size();
@@ -2027,10 +2047,6 @@
                     if (previouslySelected != null) {
                         previouslySelected.setTaskViewVisibility(false);
                     }
-
-                    if (mPositioner.showingInTaskbar()) {
-                        mTaskbarScrim.setVisibility(GONE);
-                    }
                 })
                 .start();
     }
@@ -2407,20 +2423,19 @@
 
 
             if (mFlyout.getVisibility() == View.VISIBLE) {
-                mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
+                mFlyout.animateUpdate(bubble.getFlyoutMessage(),
                         mStackAnimationController.getStackPosition(), !bubble.showDot(),
                         mAfterFlyoutHidden /* onHide */);
             } else {
                 mFlyout.setVisibility(INVISIBLE);
                 mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
-                        mStackAnimationController.getStackPosition(), getWidth(),
+                        mStackAnimationController.getStackPosition(),
                         mStackAnimationController.isStackOnLeftSide(),
                         bubble.getIconView().getDotColor() /* dotColor */,
                         expandFlyoutAfterDelay /* onLayoutComplete */,
                         mAfterFlyoutHidden /* onHide */,
                         bubble.getIconView().getDotCenter(),
-                        !bubble.showDot(),
-                        mPositioner);
+                        !bubble.showDot());
             }
             mFlyout.bringToFront();
         });
@@ -2505,6 +2520,24 @@
             return;
         }
 
+        if (show) {
+            mManageMenuScrim.setVisibility(VISIBLE);
+            mManageMenuScrim.setTranslationZ(mManageMenu.getElevation() - 1f);
+        }
+        Runnable endAction = () -> {
+            if (!show) {
+                mManageMenuScrim.setVisibility(INVISIBLE);
+                mManageMenuScrim.setTranslationZ(0f);
+            }
+        };
+
+        mManageMenuScrim.animate()
+                .setDuration(MANAGE_MENU_SCRIM_ANIM_DURATION)
+                .setInterpolator(show ? ALPHA_IN : ALPHA_OUT)
+                .alpha(show ? SCRIM_ALPHA : 0f)
+                .withEndAction(endAction)
+                .start();
+
         // If available, update the manage menu's settings option with the expanded bubble's app
         // name and icon.
         if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {
@@ -2514,7 +2547,6 @@
                     R.string.bubbles_app_settings, bubble.getAppName()));
         }
 
-        mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
         if (mExpandedBubble.getExpandedView().getTaskView() != null) {
             mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage
                     ? new Rect(0, 0, getWidth(), getHeight())
@@ -2526,7 +2558,11 @@
 
         // When the menu is open, it should be at these coordinates. The menu pops out to the right
         // in LTR and to the left in RTL.
-        final float targetX = isLtr ? mTempRect.left : mTempRect.right - mManageMenu.getWidth();
+        mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
+        final float margin = mExpandedBubble.getExpandedView().getManageButtonMargin();
+        final float targetX = isLtr
+                ? mTempRect.left - margin
+                : mTempRect.right + margin - mManageMenu.getWidth();
         final float targetY = mTempRect.bottom - mManageMenu.getHeight();
 
         final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index c73b5ee..9b7eb2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -24,12 +24,10 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
-import android.os.Looper;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.view.View;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
@@ -43,7 +41,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
 
@@ -160,14 +157,6 @@
     /** Set the proxy to commnuicate with SysUi side components. */
     void setSysuiProxy(SysuiProxy proxy);
 
-    /**
-     * Set the scrim view for bubbles.
-     *
-     * @param callback The callback made with the executor and the executor's looper that the view
-     *                 will be running on.
-     **/
-    void setBubbleScrim(View view, BiConsumer<Executor, Looper> callback);
-
     /** Set a listener to be notified of bubble expand events. */
     void setExpandListener(BubbleExpandListener listener);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b7235a3..b90283f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -82,6 +82,9 @@
     private boolean mHasNavigationBar = false;
     private boolean mHasStatusBar = false;
     private int mNavBarFrameHeight = 0;
+    private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
+    private boolean mNavigationBarCanMove = false;
+    private boolean mReverseDefaultRotation = false;
 
     @Override
     public boolean equals(Object o) {
@@ -98,6 +101,10 @@
                 && Objects.equals(mStableInsets, other.mStableInsets)
                 && mHasNavigationBar == other.mHasNavigationBar
                 && mHasStatusBar == other.mHasStatusBar
+                && mAllowSeamlessRotationDespiteNavBarMoving
+                        == other.mAllowSeamlessRotationDespiteNavBarMoving
+                && mNavigationBarCanMove == other.mNavigationBarCanMove
+                && mReverseDefaultRotation == other.mReverseDefaultRotation
                 && mNavBarFrameHeight == other.mNavBarFrameHeight;
     }
 
@@ -105,7 +112,8 @@
     public int hashCode() {
         return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
                 mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
-                mNavBarFrameHeight);
+                mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
+                mNavigationBarCanMove, mReverseDefaultRotation);
     }
 
     /**
@@ -150,6 +158,9 @@
         mDensityDpi = dl.mDensityDpi;
         mHasNavigationBar = dl.mHasNavigationBar;
         mHasStatusBar = dl.mHasStatusBar;
+        mAllowSeamlessRotationDespiteNavBarMoving = dl.mAllowSeamlessRotationDespiteNavBarMoving;
+        mNavigationBarCanMove = dl.mNavigationBarCanMove;
+        mReverseDefaultRotation = dl.mReverseDefaultRotation;
         mNavBarFrameHeight = dl.mNavBarFrameHeight;
         mNonDecorInsets.set(dl.mNonDecorInsets);
         mStableInsets.set(dl.mStableInsets);
@@ -165,6 +176,10 @@
         mDensityDpi = info.logicalDensityDpi;
         mHasNavigationBar = hasNavigationBar;
         mHasStatusBar = hasStatusBar;
+        mAllowSeamlessRotationDespiteNavBarMoving = res.getBoolean(
+            R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
+        mNavigationBarCanMove = res.getBoolean(R.bool.config_navBarCanMove);
+        mReverseDefaultRotation = res.getBoolean(R.bool.config_reverseDefaultRotation);
         recalcInsets(res);
     }
 
@@ -249,6 +264,28 @@
         return mNavBarFrameHeight;
     }
 
+    /** @return whether we can seamlessly rotate even if nav-bar can change sides. */
+    public boolean allowSeamlessRotationDespiteNavBarMoving() {
+        return mAllowSeamlessRotationDespiteNavBarMoving;
+    }
+
+    /** @return whether the navigation bar will change sides during rotation. */
+    public boolean navigationBarCanMove() {
+        return mNavigationBarCanMove;
+    }
+
+    /** @return the rotation that would make the physical display "upside down". */
+    public int getUpsideDownRotation() {
+        boolean displayHardwareIsLandscape = mWidth > mHeight;
+        if ((mRotation % 2) != 0) {
+            displayHardwareIsLandscape = !displayHardwareIsLandscape;
+        }
+        if (displayHardwareIsLandscape) {
+            return mReverseDefaultRotation ? Surface.ROTATION_270 : Surface.ROTATION_90;
+        }
+        return Surface.ROTATION_180;
+    }
+
     /** Gets the orientation of this layout */
     public int getOrientation() {
         return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 8adfac0..bb40f67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -16,11 +16,18 @@
 
 package com.android.wm.shell.common.split;
 
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
 import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
 import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -30,6 +37,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
 import android.view.WindowInsets;
@@ -39,6 +47,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.animation.Interpolators;
@@ -78,6 +87,7 @@
     private final int mDividerInsets;
     private final int mDividerSize;
 
+    private final Rect mTempRect = new Rect();
     private final Rect mRootBounds = new Rect();
     private final Rect mDividerBounds = new Rect();
     private final Rect mBounds1 = new Rect();
@@ -86,6 +96,7 @@
     private final SplitWindowManager mSplitWindowManager;
     private final DisplayImeController mDisplayImeController;
     private final ImePositionProcessor mImePositionProcessor;
+    private final DismissingParallaxPolicy mDismissingParallaxPolicy;
     private final ShellTaskOrganizer mTaskOrganizer;
 
     private Context mContext;
@@ -108,6 +119,7 @@
                 windowName, mContext, configuration, parentContainerCallbacks);
         mTaskOrganizer = taskOrganizer;
         mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
+        mDismissingParallaxPolicy = new DismissingParallaxPolicy();
 
         final Resources resources = context.getResources();
         mDividerWindowWidth = resources.getDimensionPixelSize(
@@ -185,7 +197,8 @@
         mDividerBounds.set(mRootBounds);
         mBounds1.set(mRootBounds);
         mBounds2.set(mRootBounds);
-        if (isLandscape(mRootBounds)) {
+        final boolean isLandscape = isLandscape(mRootBounds);
+        if (isLandscape) {
             position += mRootBounds.left;
             mDividerBounds.left = position - mDividerInsets;
             mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
@@ -198,6 +211,7 @@
             mBounds1.bottom = position;
             mBounds2.top = mBounds1.bottom + mDividerSize;
         }
+        mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
     }
 
     /** Inflates {@link DividerView} on the root surface. */
@@ -224,19 +238,20 @@
     void updateDivideBounds(int position) {
         updateBounds(position);
         mSplitWindowManager.setResizingSplits(true);
-        mSplitLayoutHandler.onBoundsChanging(this);
+        mSplitLayoutHandler.onLayoutChanging(this);
     }
 
     void setDividePosition(int position) {
         mDividePosition = position;
         updateBounds(mDividePosition);
-        mSplitLayoutHandler.onBoundsChanged(this);
+        mSplitLayoutHandler.onLayoutChanged(this);
         mSplitWindowManager.setResizingSplits(false);
     }
 
     /** Resets divider position. */
     public void resetDividerPosition() {
         mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+        mSplitWindowManager.setResizingSplits(false);
         updateBounds(mDividePosition);
     }
 
@@ -247,15 +262,15 @@
     public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
         switch (snapTarget.flag) {
             case FLAG_DISMISS_START:
-                mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */);
-                mSplitWindowManager.setResizingSplits(false);
+                flingDividePosition(currentPosition, snapTarget.position,
+                        () -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */));
                 break;
             case FLAG_DISMISS_END:
-                mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */);
-                mSplitWindowManager.setResizingSplits(false);
+                flingDividePosition(currentPosition, snapTarget.position,
+                        () -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */));
                 break;
             default:
-                flingDividePosition(currentPosition, snapTarget.position);
+                flingDividePosition(currentPosition, snapTarget.position, null);
                 break;
         }
     }
@@ -285,7 +300,8 @@
                 isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
     }
 
-    private void flingDividePosition(int from, int to) {
+    @VisibleForTesting
+    void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
         if (from == to) {
             // No animation run, it should stop resizing here.
             mSplitWindowManager.setResizingSplits(false);
@@ -301,6 +317,9 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 setDividePosition(to);
+                if (flingFinishedCallback != null) {
+                    flingFinishedCallback.run();
+                }
             }
 
             @Override
@@ -326,30 +345,73 @@
     /** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */
     public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
             SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
-        final Rect dividerBounds = mImePositionProcessor.adjustForIme(mDividerBounds);
-        final Rect bounds1 = mImePositionProcessor.adjustForIme(mBounds1);
-        final Rect bounds2 = mImePositionProcessor.adjustForIme(mBounds2);
         final SurfaceControl dividerLeash = getDividerLeash();
         if (dividerLeash != null) {
-            t.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
-                    // Resets layer of divider bar to make sure it is always on top.
-                    .setLayer(dividerLeash, Integer.MAX_VALUE);
+            t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+            // Resets layer of divider bar to make sure it is always on top.
+            t.setLayer(dividerLeash, Integer.MAX_VALUE);
+        }
+        t.setPosition(leash1, mBounds1.left, mBounds1.top)
+                .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
+        t.setPosition(leash2, mBounds2.left, mBounds2.top)
+                .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
+
+        if (mImePositionProcessor.adjustSurfaceLayoutForIme(
+                t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
+            return;
         }
 
-        t.setPosition(leash1, bounds1.left, bounds1.top)
-                .setWindowCrop(leash1, bounds1.width(), bounds1.height());
-
-        t.setPosition(leash2, bounds2.left, bounds2.top)
-                .setWindowCrop(leash2, bounds2.width(), bounds2.height());
-
-        mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2);
+        mDismissingParallaxPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
     }
 
     /** Apply recorded task layout to the {@link WindowContainerTransaction}. */
     public void applyTaskChanges(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
-        wct.setBounds(task1.token, mImePositionProcessor.adjustForIme(mBounds1))
-                .setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
+        if (mImePositionProcessor.applyTaskLayoutForIme(wct, task1.token, task2.token)) {
+            return;
+        }
+
+        wct.setBounds(task1.token, mBounds1)
+                .setBounds(task2.token, mBounds2);
+    }
+
+    /**
+     * Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
+     * restore shifted configuration bounds if it's no longer shifted.
+     */
+    public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY,
+            ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
+        if (offsetX == 0 && offsetY == 0) {
+            wct.setBounds(taskInfo1.token, mBounds1);
+            wct.setAppBounds(taskInfo1.token, null);
+            wct.setScreenSizeDp(taskInfo1.token,
+                    SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+
+            wct.setBounds(taskInfo2.token, mBounds2);
+            wct.setAppBounds(taskInfo2.token, null);
+            wct.setScreenSizeDp(taskInfo2.token,
+                    SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+        } else {
+            mTempRect.set(taskInfo1.configuration.windowConfiguration.getBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setBounds(taskInfo1.token, mTempRect);
+            mTempRect.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setAppBounds(taskInfo1.token, mTempRect);
+            wct.setScreenSizeDp(taskInfo1.token,
+                    taskInfo1.configuration.screenWidthDp,
+                    taskInfo1.configuration.screenHeightDp);
+
+            mTempRect.set(taskInfo2.configuration.windowConfiguration.getBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setBounds(taskInfo2.token, mTempRect);
+            mTempRect.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setAppBounds(taskInfo2.token, mTempRect);
+            wct.setScreenSizeDp(taskInfo2.token,
+                    taskInfo2.configuration.screenWidthDp,
+                    taskInfo2.configuration.screenHeightDp);
+        }
     }
 
     /** Handles layout change event. */
@@ -359,10 +421,18 @@
         void onSnappedToDismiss(boolean snappedToEnd);
 
         /** Calls when the bounds is changing due to animation or dragging divider bar. */
-        void onBoundsChanging(SplitLayout layout);
+        void onLayoutChanging(SplitLayout layout);
 
         /** Calls when the target bounds changed. */
-        void onBoundsChanged(SplitLayout layout);
+        void onLayoutChanged(SplitLayout layout);
+
+        /**
+         * Notifies when the layout shifted. So the layout handler can shift configuration
+         * bounds correspondingly to make sure client apps won't get configuration changed or
+         * relaunch. If the layout is no longer shifted, layout handler should restore shifted
+         * configuration bounds.
+         */
+        void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout);
 
         /** Calls when user double tapped on the divider bar. */
         default void onDoubleTappedDivider() {
@@ -373,6 +443,106 @@
         int getSplitItemPosition(WindowContainerToken token);
     }
 
+    /**
+     * Calculates and applies proper dismissing parallax offset and dimming value to hint users
+     * dismissing gesture.
+     */
+    private class DismissingParallaxPolicy {
+        // The current dismissing side.
+        int mDismissingSide = DOCKED_INVALID;
+
+        // The parallax offset to hint the dismissing side and progress.
+        final Point mDismissingParallaxOffset = new Point();
+
+        // The dimming value to hint the dismissing side and progress.
+        float mDismissingDimValue = 0.0f;
+
+        /**
+         * Applies a parallax to the task to hint dismissing progress.
+         *
+         * @param position the split position to apply dismissing parallax effect
+         * @param isLandscape indicates whether it's splitting horizontally or vertically
+         */
+        void applyDividerPosition(int position, boolean isLandscape) {
+            mDismissingSide = DOCKED_INVALID;
+            mDismissingParallaxOffset.set(0, 0);
+            mDismissingDimValue = 0;
+
+            int totalDismissingDistance = 0;
+            if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
+                mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
+                totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
+                                - mDividerSnapAlgorithm.getFirstSplitTarget().position;
+            } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
+                mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
+                totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
+                                - mDividerSnapAlgorithm.getDismissEndTarget().position;
+            }
+
+            if (mDismissingSide != DOCKED_INVALID) {
+                float fraction = Math.max(0,
+                        Math.min(mDividerSnapAlgorithm.calculateDismissingFraction(position), 1f));
+                mDismissingDimValue = DIM_INTERPOLATOR.getInterpolation(fraction);
+                fraction = calculateParallaxDismissingFraction(fraction, mDismissingSide);
+                if (isLandscape) {
+                    mDismissingParallaxOffset.x = (int) (fraction * totalDismissingDistance);
+                } else {
+                    mDismissingParallaxOffset.y = (int) (fraction * totalDismissingDistance);
+                }
+            }
+        }
+
+        /**
+         * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+         * slowing down parallax effect
+         */
+        private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
+            float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+
+            // Less parallax at the top, just because.
+            if (dockSide == WindowManager.DOCKED_TOP) {
+                result /= 2f;
+            }
+            return result;
+        }
+
+        /** Applies parallax offset and dimming value to the root surface at the dismissing side. */
+        boolean adjustDismissingSurface(SurfaceControl.Transaction t,
+                SurfaceControl leash1, SurfaceControl leash2,
+                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+            SurfaceControl targetLeash, targetDimLayer;
+            switch (mDismissingSide) {
+                case DOCKED_TOP:
+                case DOCKED_LEFT:
+                    targetLeash = leash1;
+                    targetDimLayer = dimLayer1;
+                    mTempRect.set(mBounds1);
+                    break;
+                case DOCKED_BOTTOM:
+                case DOCKED_RIGHT:
+                    targetLeash = leash2;
+                    targetDimLayer = dimLayer2;
+                    mTempRect.set(mBounds2);
+                    break;
+                case DOCKED_INVALID:
+                default:
+                    t.setAlpha(dimLayer1, 0).hide(dimLayer1);
+                    t.setAlpha(dimLayer2, 0).hide(dimLayer2);
+                    return false;
+            }
+
+            t.setPosition(targetLeash,
+                    mTempRect.left + mDismissingParallaxOffset.x,
+                    mTempRect.top + mDismissingParallaxOffset.y);
+            // Transform the screen-based split bounds to surface-based crop bounds.
+            mTempRect.offsetTo(-mDismissingParallaxOffset.x, -mDismissingParallaxOffset.y);
+            t.setWindowCrop(targetLeash, mTempRect);
+            t.setAlpha(targetDimLayer, mDismissingDimValue)
+                    .setVisibility(targetDimLayer, mDismissingDimValue > 0.001f);
+            return true;
+        }
+    }
+
     /** Records IME top offset changes and updates SplitLayout correspondingly. */
     private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor {
         /**
@@ -427,6 +597,18 @@
                     && !isFloating && !isLandscape(mRootBounds) && showing;
             mTargetYOffset = needOffset ? getTargetYOffset() : 0;
 
+            if (mTargetYOffset != mLastYOffset) {
+                // Freeze the configuration size with offset to prevent app get a configuration
+                // changed or relaunch. This is required to make sure client apps will calculate
+                // insets properly after layout shifted.
+                if (mTargetYOffset == 0) {
+                    mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this);
+                } else {
+                    mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset,
+                            SplitLayout.this);
+                }
+            }
+
             // Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
             // ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
             // because DividerView won't receive onImeVisibilityChanged callback after it being
@@ -441,7 +623,7 @@
         public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
             if (displayId != mDisplayId) return;
             onProgress(getProgress(imeTop));
-            mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+            mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
         }
 
         @Override
@@ -449,7 +631,7 @@
                 SurfaceControl.Transaction t) {
             if (displayId != mDisplayId || cancel) return;
             onProgress(1.0f);
-            mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+            mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
         }
 
         @Override
@@ -459,7 +641,7 @@
             if (!controlling && mImeShown) {
                 reset();
                 mSplitWindowManager.setInteractive(true);
-                mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+                mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
             }
         }
 
@@ -491,24 +673,61 @@
             return start + (end - start) * progress;
         }
 
-        private void reset() {
+        void reset() {
             mImeShown = false;
             mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
             mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
             mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f;
         }
 
-        /* Adjust bounds with IME offset. */
-        private Rect adjustForIme(Rect bounds) {
-            final Rect temp = new Rect(bounds);
-            if (mYOffsetForIme != 0) temp.offset(0, mYOffsetForIme);
-            return temp;
+        /**
+         * Applies adjusted task layout for showing IME.
+         *
+         * @return {@code false} if there's no need to adjust, otherwise {@code true}
+         */
+        boolean applyTaskLayoutForIme(WindowContainerTransaction wct,
+                WindowContainerToken token1, WindowContainerToken token2) {
+            if (mYOffsetForIme == 0) return false;
+
+            mTempRect.set(mBounds1);
+            mTempRect.offset(0, mYOffsetForIme);
+            wct.setBounds(token1, mTempRect);
+
+            mTempRect.set(mBounds2);
+            mTempRect.offset(0, mYOffsetForIme);
+            wct.setBounds(token2, mTempRect);
+
+            return true;
         }
 
-        private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1,
-                SurfaceControl dimLayer2) {
+        /**
+         * Adjusts surface layout while showing IME.
+         *
+         * @return {@code false} if there's no need to adjust, otherwise {@code true}
+         */
+        boolean adjustSurfaceLayoutForIme(SurfaceControl.Transaction t,
+                SurfaceControl dividerLeash, SurfaceControl leash1, SurfaceControl leash2,
+                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+            if (mYOffsetForIme == 0) return false;
+
+            if (dividerLeash != null) {
+                mTempRect.set(mDividerBounds);
+                mTempRect.offset(0, mYOffsetForIme);
+                t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
+            }
+
+            mTempRect.set(mBounds1);
+            mTempRect.offset(0, mYOffsetForIme);
+            t.setPosition(leash1, mTempRect.left, mTempRect.top);
+
+            mTempRect.set(mBounds2);
+            mTempRect.offset(0, mYOffsetForIme);
+            t.setPosition(leash2, mTempRect.left, mTempRect.top);
+
             t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
             t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
+
+            return true;
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 9bcc3ac..5b9d7b80 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -151,10 +151,8 @@
                 final Rect rightHitRegion = new Rect();
                 final Rect rightDrawRegion = bottomOrRightBounds;
 
-                displayRegion.splitVertically(leftHitRegion, fullscreenHitRegion, rightHitRegion);
+                displayRegion.splitVertically(leftHitRegion, rightHitRegion);
 
-                mTargets.add(
-                        new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
                 mTargets.add(new Target(TYPE_SPLIT_LEFT, leftHitRegion, leftDrawRegion));
                 mTargets.add(new Target(TYPE_SPLIT_RIGHT, rightHitRegion, rightDrawRegion));
 
@@ -165,10 +163,8 @@
                 final Rect bottomDrawRegion = bottomOrRightBounds;
 
                 displayRegion.splitHorizontally(
-                        topHitRegion, fullscreenHitRegion, bottomHitRegion);
+                        topHitRegion, bottomHitRegion);
 
-                mTargets.add(
-                        new Target(TYPE_FULLSCREEN, fullscreenHitRegion, fullscreenDrawRegion));
                 mTargets.add(new Target(TYPE_SPLIT_TOP, topHitRegion, topDrawRegion));
                 mTargets.add(new Target(TYPE_SPLIT_BOTTOM, bottomHitRegion, bottomDrawRegion));
             }
@@ -269,7 +265,6 @@
          * Updates the session data based on the current state of the system.
          */
         void update() {
-
             List<ActivityManager.RunningTaskInfo> tasks =
                     mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
             if (!tasks.isEmpty()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
new file mode 100644
index 0000000..5fb3297
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.freeform;
+
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.provider.Settings;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.SurfaceControl;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.io.PrintWriter;
+
+/**
+ * {@link ShellTaskOrganizer.TaskListener} for {@link
+ * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}.
+ */
+public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
+    private static final String TAG = "FreeformTaskListener";
+
+    private final SyncTransactionQueue mSyncQueue;
+
+    private final SparseArray<State> mTasks = new SparseArray<>();
+
+    private static class State {
+        RunningTaskInfo mTaskInfo;
+        SurfaceControl mLeash;
+    }
+
+    public FreeformTaskListener(SyncTransactionQueue syncQueue) {
+        mSyncQueue = syncQueue;
+    }
+
+    @Override
+    public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+        if (mTasks.get(taskInfo.taskId) != null) {
+            throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
+        }
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d",
+                taskInfo.taskId);
+        final State state = new State();
+        state.mTaskInfo = taskInfo;
+        state.mLeash = leash;
+        mTasks.put(taskInfo.taskId, state);
+
+        final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
+        mSyncQueue.runInSync(t -> {
+            Point taskPosition = taskInfo.positionInParent;
+            t.setPosition(leash, taskPosition.x, taskPosition.y)
+                    .setWindowCrop(leash, taskBounds.width(), taskBounds.height())
+                    .show(leash);
+        });
+    }
+
+    @Override
+    public void onTaskVanished(RunningTaskInfo taskInfo) {
+        State state = mTasks.get(taskInfo.taskId);
+        if (state == null) {
+            Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
+            return;
+        }
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
+                taskInfo.taskId);
+        mTasks.remove(taskInfo.taskId);
+    }
+
+    @Override
+    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+        State state = mTasks.get(taskInfo.taskId);
+        if (state == null) {
+            throw new RuntimeException(
+                    "Task info changed before appearing: #" + taskInfo.taskId);
+        }
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
+                taskInfo.taskId);
+        state.mTaskInfo = taskInfo;
+
+        final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
+        final SurfaceControl leash = state.mLeash;
+        mSyncQueue.runInSync(t -> {
+            Point taskPosition = taskInfo.positionInParent;
+            t.setPosition(leash, taskPosition.x, taskPosition.y)
+                    .setWindowCrop(leash, taskBounds.width(), taskBounds.height())
+                    .show(leash);
+        });
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + this);
+        pw.println(innerPrefix + mTasks.size() + " tasks");
+    }
+
+    @Override
+    public String toString() {
+        return TAG;
+    }
+
+    /**
+     * Checks if freeform support is enabled in system.
+     *
+     * @param context context used to check settings and package manager.
+     * @return {@code true} if freeform is enabled, {@code false} if not.
+     */
+    public static boolean isFreeformEnabled(Context context) {
+        return context.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+                || Settings.Global.getInt(context.getContentResolver(),
+                DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+    }
+
+    /**
+     * Creates {@link FreeformTaskListener} if freeform is enabled.
+     */
+    public static FreeformTaskListener create(Context context,
+            SyncTransactionQueue syncQueue) {
+        if (!isFreeformEnabled(context)) {
+            return null;
+        }
+
+        return new FreeformTaskListener(syncQueue);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index 9bed40d..067f808 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -20,6 +20,8 @@
 import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
 import static android.view.WindowManager.DOCKED_RIGHT;
 
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
 import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
 import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;
 
@@ -100,10 +102,6 @@
     private static final float MINIMIZE_DOCK_SCALE = 0f;
     private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
 
-    private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
-            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
-    private static final PathInterpolator DIM_INTERPOLATOR =
-            new PathInterpolator(.23f, .87f, .52f, -0.11f);
     private static final Interpolator IME_ADJUST_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index 97461e6..d0491e95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -21,6 +21,7 @@
 import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.view.ContextThemeWrapper;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.animation.LinearInterpolator;
@@ -31,7 +32,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.view.ContextThemeWrapper;
 
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 21bc889..ff333c8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -130,7 +130,7 @@
      */
     public boolean getSettingsTapsAppToExit(ContentResolver resolver, int userId) {
         return Settings.Secure.getIntForUser(resolver,
-                Settings.Secure.TAPS_APP_TO_EXIT, 0, userId) == 1;
+                Settings.Secure.TAPS_APP_TO_EXIT, 1, userId) == 1;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index f58c6b1..88f3375 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -32,6 +32,8 @@
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.os.SystemProperties;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
@@ -44,7 +46,6 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.appcompat.view.ContextThemeWrapper;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index d77619a..1d238a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -137,11 +137,6 @@
         public void onPipAnimationStart(TaskInfo taskInfo,
                 PipAnimationController.PipTransitionAnimator animator) {
             final int direction = animator.getTransitionDirection();
-            if (direction == TRANSITION_DIRECTION_TO_PIP) {
-                // TODO (b//169221267): Add jank listener for transactions without buffer updates.
-                //InteractionJankMonitor.getInstance().begin(
-                //        InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 2000);
-            }
             sendOnPipTransitionStarted(direction);
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index ae17a93..ea587c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.util.RotationUtils.deltaRotation;
+import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_PIP;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
@@ -126,6 +127,12 @@
             return true;
         }
 
+        // We only support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
+        // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
+        if (info.getType() != TRANSIT_PIP && info.getType() != TRANSIT_OPEN) {
+            return false;
+        }
+
         // Search for an Enter PiP transition (along with a show wallpaper one)
         TransitionInfo.Change enterPip = null;
         TransitionInfo.Change wallpaper = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index dedc566..dbf603c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
-import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 
 import android.app.PictureInPictureParams;
 import android.app.TaskInfo;
@@ -57,12 +56,6 @@
                 public void onPipAnimationStart(TaskInfo taskInfo,
                         PipAnimationController.PipTransitionAnimator animator) {
                     final int direction = animator.getTransitionDirection();
-                    if (direction == TRANSITION_DIRECTION_TO_PIP) {
-                        // TODO (b//169221267): Add jank listener for transactions without buffer
-                        //  updates.
-                        //InteractionJankMonitor.getInstance().begin(
-                        //        InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 2000);
-                    }
                     sendOnPipTransitionStarted(direction);
                 }
 
@@ -76,12 +69,6 @@
                     }
                     onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
                     sendOnPipTransitionFinished(direction);
-                    if (direction == TRANSITION_DIRECTION_TO_PIP) {
-                        // TODO (b//169221267): Add jank listener for transactions without buffer
-                        //  updates.
-                        //InteractionJankMonitor.getInstance().end(
-                        //        InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
-                    }
                 }
 
                 @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 62b50c5..92c0099 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -21,7 +21,15 @@
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION;
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SNAP_AFTER_RESIZE;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 
 import android.app.ActivityManager;
@@ -52,6 +60,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.wm.shell.R;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayChangeController;
@@ -567,8 +576,37 @@
         mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds, overlay);
     }
 
+    private String getTransitionTag(int direction) {
+        switch (direction) {
+            case TRANSITION_DIRECTION_TO_PIP:
+                return "TRANSITION_TO_PIP";
+            case TRANSITION_DIRECTION_LEAVE_PIP:
+                return "TRANSITION_LEAVE_PIP";
+            case TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN:
+                return "TRANSITION_LEAVE_PIP_TO_SPLIT_SCREEN";
+            case TRANSITION_DIRECTION_REMOVE_STACK:
+                return "TRANSITION_REMOVE_STACK";
+            case TRANSITION_DIRECTION_SNAP_AFTER_RESIZE:
+                return "TRANSITION_SNAP_AFTER_RESIZE";
+            case TRANSITION_DIRECTION_USER_RESIZE:
+                return "TRANSITION_USER_RESIZE";
+            case TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND:
+                return "TRANSITION_EXPAND_OR_UNEXPAND";
+            default:
+                return "TRANSITION_LEAVE_UNKNOWN";
+        }
+    }
+
     @Override
     public void onPipTransitionStarted(int direction, Rect pipBounds) {
+        // Begin InteractionJankMonitor with PIP transition CUJs
+        final InteractionJankMonitor.Configuration.Builder builder =
+                InteractionJankMonitor.Configuration.Builder.withSurface(
+                        CUJ_PIP_TRANSITION, mContext, mPipTaskOrganizer.getSurfaceControl())
+                .setTag(getTransitionTag(direction))
+                .setTimeout(2000);
+        InteractionJankMonitor.getInstance().begin(builder);
+
         if (isOutPipDirection(direction)) {
             // Exiting PIP, save the reentry state to restore to when re-entering.
             saveReentryState(pipBounds);
@@ -607,6 +645,9 @@
     }
 
     private void onPipTransitionFinishedOrCanceled(int direction) {
+        // End InteractionJankMonitor with PIP transition by CUJs
+        InteractionJankMonitor.getInstance().end(CUJ_PIP_TRANSITION);
+
         // Re-enable touches after the animation completes
         mTouchHandler.setTouchEnabled(true);
         mTouchHandler.onPinnedStackAnimationEnded(direction);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 0e76da7..e86462f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -81,6 +81,12 @@
      */
     void onKeyguardOccludedChanged(boolean occluded);
 
+    /**
+     * Called when the visibility of the keyguard changes.
+     * @param showing Indicates if the keyguard is now visible.
+     */
+    void onKeyguardVisibilityChanged(boolean showing);
+
     /** Get a string representation of a stage type */
     static String stageTypeToString(@StageType int stage) {
         switch (stage) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 988efb6..7804c77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -172,6 +172,10 @@
         mStageCoordinator.onKeyguardOccludedChanged(occluded);
     }
 
+    public void onKeyguardVisibilityChanged(boolean showing) {
+        mStageCoordinator.onKeyguardVisibilityChanged(showing);
+    }
+
     public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
         mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
     }
@@ -371,6 +375,13 @@
                 }
             });
         }
+
+        @Override
+        public void onKeyguardVisibilityChanged(boolean showing) {
+            mMainExecutor.execute(() -> {
+                SplitScreenController.this.onKeyguardVisibilityChanged(showing);
+            });
+        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index d1aa2d7..29e9917 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -136,7 +136,10 @@
     /** Whether the device is supporting legacy split or not. */
     private boolean mUseLegacySplit;
 
-    @SplitScreen.StageType int mDismissTop = NO_DISMISS;
+    @SplitScreen.StageType private int mDismissTop = NO_DISMISS;
+
+    /** The target stage to dismiss to when unlock after folded. */
+    @SplitScreen.StageType private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
 
     private final Runnable mOnTransitionAnimationComplete = () -> {
         // If still playing, let it finish.
@@ -422,7 +425,7 @@
         if (mSideStageListener.mVisible && updateBounds) {
             if (wct == null) {
                 // onBoundsChanged builds/applies a wct with the contents of updateWindowBounds.
-                onBoundsChanged(mSplitLayout);
+                onLayoutChanged(mSplitLayout);
             } else {
                 updateWindowBounds(mSplitLayout, wct);
             }
@@ -443,6 +446,13 @@
         mKeyguardOccluded = occluded;
     }
 
+    void onKeyguardVisibilityChanged(boolean showing) {
+        if (!showing && mMainStage.isActive()
+                && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+            exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage);
+        }
+    }
+
     void exitSplitScreen() {
         exitSplitScreen(null /* childrenToTop */);
     }
@@ -458,6 +468,7 @@
         mTaskOrganizer.applyTransaction(wct);
         // Reset divider position.
         mSplitLayout.resetDividerPosition();
+        mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
     }
 
     /**
@@ -732,12 +743,12 @@
     }
 
     @Override
-    public void onBoundsChanging(SplitLayout layout) {
+    public void onLayoutChanging(SplitLayout layout) {
         mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
     }
 
     @Override
-    public void onBoundsChanged(SplitLayout layout) {
+    public void onLayoutChanged(SplitLayout layout) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         updateWindowBounds(layout, wct);
         mSyncQueue.queue(wct);
@@ -781,6 +792,18 @@
     }
 
     @Override
+    public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+        final StageTaskListener topLeftStage =
+                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+        final StageTaskListener bottomRightStage =
+                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
+                bottomRightStage.mRootTaskInfo);
+        mTaskOrganizer.applyTransaction(wct);
+    }
+
+    @Override
     public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
         mDisplayAreaInfo = displayAreaInfo;
         if (mSplitLayout == null) {
@@ -802,14 +825,19 @@
         if (mSplitLayout != null
                 && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
                 && mMainStage.isActive()) {
-            onBoundsChanged(mSplitLayout);
+            onLayoutChanged(mSplitLayout);
             mSyncQueue.runInSync(t -> applyDividerVisibility(t));
         }
     }
 
     private void onFoldedStateChanged(boolean folded) {
-        if (folded && mMainStage.isActive()) {
-            exitSplitScreen(mMainStage);
+        mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+        if (!folded) return;
+
+        if (mMainStage.isFocused()) {
+            mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
+        } else if (mSideStage.isFocused()) {
+            mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
         }
     }
 
@@ -1097,7 +1125,7 @@
                 null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
                 new android.graphics.Point(0, 0) /* position */, bounds, bounds,
                 new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
-                null /* taskInfo */, TYPE_DOCK_DIVIDER);
+                null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 4f73fee..c47353a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -97,6 +97,15 @@
         return mChildrenTaskInfo.contains(taskId);
     }
 
+    /** @return {@code true} if this listener contains the currently focused task. */
+    boolean isFocused() {
+        if (mRootTaskInfo.isFocused) return true;
+        for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+            if (mChildrenTaskInfo.valueAt(i).isFocused) return true;
+        }
+        return false;
+    }
+
     @Override
     @CallSuper
     public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 7f42fe9..b584038 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -23,6 +23,10 @@
 import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -31,8 +35,10 @@
 import static android.view.WindowManager.TRANSIT_RELAUNCH;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -59,6 +65,7 @@
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
+import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
@@ -67,9 +74,12 @@
 import android.window.WindowContainerTransaction;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -96,6 +106,7 @@
             SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
 
     private final TransactionPool mTransactionPool;
+    private final DisplayController mDisplayController;
     private final Context mContext;
     private final ShellExecutor mMainExecutor;
     private final ShellExecutor mAnimExecutor;
@@ -113,8 +124,10 @@
 
     private ScreenRotationAnimation mRotationAnimation;
 
-    DefaultTransitionHandler(@NonNull TransactionPool transactionPool, Context context,
+    DefaultTransitionHandler(@NonNull DisplayController displayController,
+            @NonNull TransactionPool transactionPool, Context context,
             @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
+        mDisplayController = displayController;
         mTransactionPool = transactionPool;
         mContext = context;
         mMainExecutor = mainExecutor;
@@ -125,6 +138,110 @@
         AttributeCache.init(context);
     }
 
+    @VisibleForTesting
+    static boolean isRotationSeamless(@NonNull TransitionInfo info,
+            DisplayController displayController) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                "Display is rotating, check if it should be seamless.");
+        boolean checkedDisplayLayout = false;
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+
+            // Only look at changing things. showing/hiding don't need to rotate.
+            if (change.getMode() != TRANSIT_CHANGE) continue;
+
+            // This container isn't rotating, so we can ignore it.
+            if (change.getEndRotation() == change.getStartRotation()) continue;
+
+            if ((change.getFlags() & FLAG_IS_DISPLAY) != 0) {
+                // In the presence of System Alert windows we can not seamlessly rotate.
+                if ((change.getFlags() & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                            "  display has system alert windows, so not seamless.");
+                    return false;
+                }
+            } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+                if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                            "  wallpaper is participating but isn't seamless.");
+                    return false;
+                }
+            } else if (change.getTaskInfo() != null) {
+                // We only enable seamless rotation if all the visible task windows requested it.
+                if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                            "  task %s isn't requesting seamless, so not seamless.",
+                            change.getTaskInfo().taskId);
+                    return false;
+                }
+
+                // This is the only way to get display-id currently, so we will check display
+                // capabilities here
+                if (!checkedDisplayLayout) {
+                    // only need to check display once.
+                    checkedDisplayLayout = true;
+                    final DisplayLayout displayLayout = displayController.getDisplayLayout(
+                            change.getTaskInfo().displayId);
+                    // For the upside down rotation we don't rotate seamlessly as the navigation
+                    // bar moves position. Note most apps (using orientation:sensor or user as
+                    // opposed to fullSensor) will not enter the reverse portrait orientation, so
+                    // actually the orientation won't change at all.
+                    int upsideDownRotation = displayLayout.getUpsideDownRotation();
+                    if (change.getStartRotation() == upsideDownRotation
+                            || change.getEndRotation() == upsideDownRotation) {
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                                "  rotation involves upside-down portrait, so not seamless.");
+                        return false;
+                    }
+
+                    // If the navigation bar can't change sides, then it will jump when we change
+                    // orientations and we don't rotate seamlessly - unless that is allowed, eg.
+                    // with gesture navigation where the navbar is low-profile enough that this
+                    // isn't very noticeable.
+                    if (!displayLayout.allowSeamlessRotationDespiteNavBarMoving()
+                            && (!(displayLayout.navigationBarCanMove()
+                                    && (change.getStartAbsBounds().width()
+                                            != change.getStartAbsBounds().height())))) {
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                                "  nav bar changes sides, so not seamless.");
+                        return false;
+                    }
+                }
+            }
+        }
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  Rotation IS seamless.");
+        return true;
+    }
+
+    /**
+     * Gets the rotation animation for the topmost task. Assumes that seamless is checked
+     * elsewhere, so it will default SEAMLESS to ROTATE.
+     */
+    private int getRotationAnimation(@NonNull TransitionInfo info) {
+        // Traverse in top-to-bottom order so that the first task is top-most
+        for (int i = 0; i < info.getChanges().size(); ++i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+
+            // Only look at changing things. showing/hiding don't need to rotate.
+            if (change.getMode() != TRANSIT_CHANGE) continue;
+
+            // This container isn't rotating, so we can ignore it.
+            if (change.getEndRotation() == change.getStartRotation()) continue;
+
+            if (change.getTaskInfo() != null) {
+                final int anim = change.getRotationAnimation();
+                if (anim == ROTATION_ANIMATION_UNSPECIFIED
+                        // Fallback animation for seamless should also be default.
+                        || anim == ROTATION_ANIMATION_SEAMLESS) {
+                    return ROTATION_ANIMATION_ROTATE;
+                }
+                return anim;
+            }
+        }
+        return ROTATION_ANIMATION_ROTATE;
+    }
+
     @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startTransaction,
@@ -132,6 +249,15 @@
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "start default transition animation, info = %s", info);
+
+        // Fallback for screen wake. This just immediately finishes since there is no
+        // animation for screen-wake.
+        if (info.getType() == WindowManager.TRANSIT_WAKE) {
+            startTransaction.apply();
+            finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+            return true;
+        }
+
         if (mAnimations.containsKey(transition)) {
             throw new IllegalStateException("Got a duplicate startAnimation call for "
                     + transition);
@@ -158,11 +284,15 @@
             if (info.getType() == TRANSIT_CHANGE && change.getMode() == TRANSIT_CHANGE
                     && (change.getEndRotation() != change.getStartRotation())
                     && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
-                mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
-                        mTransactionPool, startTransaction, change, info.getRootLeash());
-                mRotationAnimation.startAnimation(animations, onAnimFinish,
-                        mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor);
-                continue;
+                boolean isSeamless = isRotationSeamless(info, mDisplayController);
+                final int anim = getRotationAnimation(info);
+                if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) {
+                    mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
+                            mTransactionPool, startTransaction, change, info.getRootLeash());
+                    mRotationAnimation.startAnimation(animations, onAnimFinish,
+                            mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor);
+                    continue;
+                }
             }
 
             if (change.getMode() == TRANSIT_CHANGE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index f432049..bda884c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -107,6 +107,7 @@
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Checking filter %s",
                         mFilters.get(i));
                 if (mFilters.get(i).first.matches(info)) {
+                    Slog.d(TAG, "Found filter" + mFilters.get(i));
                     pendingRemote = mFilters.get(i).second;
                     // Add to requested list so that it can be found for merge requests.
                     mRequestedRemotes.put(transition, pendingRemote);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 01ef2a6..09dfabf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -54,6 +54,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
@@ -113,15 +114,16 @@
     private final ArrayList<ActiveTransition> mActiveTransitions = new ArrayList<>();
 
     public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
-            @NonNull Context context, @NonNull ShellExecutor mainExecutor,
-            @NonNull ShellExecutor animExecutor) {
+            @NonNull DisplayController displayController, @NonNull Context context,
+            @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
         mOrganizer = organizer;
         mContext = context;
         mMainExecutor = mainExecutor;
         mAnimExecutor = animExecutor;
         mPlayerImpl = new TransitionPlayerImpl();
         // The very last handler (0 in the list) should be the default one.
-        mHandlers.add(new DefaultTransitionHandler(pool, context, mainExecutor, animExecutor));
+        mHandlers.add(new DefaultTransitionHandler(displayController, pool, context, mainExecutor,
+                animExecutor));
         // Next lowest priority is remote transitions.
         mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor);
         mHandlers.add(mRemoteTransitionHandler);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 0f0a4ab..e987d0e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.pip
 
+import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.FlakyTest
@@ -23,8 +24,10 @@
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toLayerName
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -32,8 +35,21 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test Pip launch.
+ * Test entering pip from an app by interacting with the app UI
+ *
  * To run this test: `atest WMShellFlickerTests:EnterPipTest`
+ *
+ * Actions:
+ *     Launch an app in full screen
+ *     Press an "enter pip" button to put [pipApp] in pip mode
+ *
+ * Notes:
+ *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ *        are inherited [PipTransition]
+ *     2. Part of the test setup occurs automatically via
+ *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ *        including configuring navigation mode, initial orientation and ensuring no
+ *        apps are running before setup
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
@@ -41,6 +57,9 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group3
 class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+    /**
+     * Defines the transition used to run the test
+     */
     override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
         get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
             transitions {
@@ -49,6 +68,9 @@
             }
         }
 
+    /**
+     * Checks [pipApp] window remains visible throughout the animation
+     */
     @Presubmit
     @Test
     fun pipAppWindowAlwaysVisible() {
@@ -57,6 +79,9 @@
         }
     }
 
+    /**
+     * Checks [pipApp] layer remains visible throughout the animation
+     */
     @Presubmit
     @Test
     fun pipAppLayerAlwaysVisible() {
@@ -65,19 +90,89 @@
         }
     }
 
-    @FlakyTest
+    /**
+     * Checks that the pip app window remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Postsubmit
     @Test
-    fun pipWindowBecomesVisible() {
+    fun pipWindowRemainInsideVisibleBounds() {
         testSpec.assertWm {
-            invoke("pipWindowIsNotVisible") {
-                verify("Has no pip window").that(it.wmState.hasPipWindow()).isTrue()
-            }.then().invoke("pipWindowIsVisible") {
-                verify("Has pip window").that(it.wmState.hasPipWindow()).isTrue()
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the pip app layer remains inside the display bounds throughout the whole
+     * animation
+     */
+    @Postsubmit
+    @Test
+    fun pipLayerRemainInsideVisibleBounds() {
+        testSpec.assertLayers {
+            coversAtMost(displayBounds, pipApp.component)
+        }
+    }
+
+    /**
+     * Checks that the visible region of [pipApp] always reduces during the animation
+     */
+    @Postsubmit
+    @Test
+    fun pipLayerReduces() {
+        val layerName = pipApp.component.toLayerName()
+        testSpec.assertLayers {
+            val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+            pipLayerList.zipWithNext { previous, current ->
+                current.visibleRegion.coversAtMost(previous.visibleRegion.region)
             }
         }
     }
 
+    /**
+     * Checks that [pipApp] window becomes pinned
+     */
+    @Postsubmit
+    @Test
+    fun pipWindowBecomesPinned() {
+        testSpec.assertWm {
+            invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp.component) }
+                .then()
+                .invoke("pipWindowIsPinned") { it.isPinned(pipApp.component) }
+        }
+    }
+
+    /**
+     * Checks [LAUNCHER_COMPONENT] layer remains visible throughout the animation
+     */
+    @Postsubmit
+    @Test
+    fun launcherLayerBecomesVisible() {
+        testSpec.assertLayers {
+            isInvisible(LAUNCHER_COMPONENT)
+                .then()
+                .isVisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks the focus doesn't change during the animation
+     */
+    @FlakyTest
+    @Test
+    fun focusDoesNotChange() {
+        testSpec.assertEventLog {
+            this.focusDoesNotChange()
+        }
+    }
+
     companion object {
+        /**
+         * Creates the test configurations.
+         *
+         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+         * repetitions, screen orientation and navigation modes.
+         */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
index 6644eaf..5c1bcb9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
@@ -63,7 +63,7 @@
         mFlyoutMessage.senderName = "Josh";
         mFlyoutMessage.message = "Hello";
 
-        mFlyout = new BubbleFlyoutView(getContext());
+        mFlyout = new BubbleFlyoutView(getContext(), mPositioner);
 
         mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text);
         mSenderName = mFlyout.findViewById(R.id.bubble_flyout_name);
@@ -75,9 +75,8 @@
     public void testShowFlyout_isVisible() {
         mFlyout.setupFlyoutStartingAsDot(
                 mFlyoutMessage,
-                new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
-                false,
-                mPositioner);
+                new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter,
+                false);
         mFlyout.setVisibility(View.VISIBLE);
 
         assertEquals("Hello", mFlyoutText.getText());
@@ -89,9 +88,8 @@
     public void testFlyoutHide_runsCallback() {
         Runnable after = mock(Runnable.class);
         mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
-                new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
-                false,
-                mPositioner);
+                new PointF(100, 100), true, Color.WHITE, null, after, mDotCenter,
+                false);
         mFlyout.hideFlyout();
 
         verify(after).run();
@@ -100,9 +98,8 @@
     @Test
     public void testSetCollapsePercent() {
         mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
-                new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
-                false,
-                mPositioner);
+                new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter,
+                false);
         mFlyout.setVisibility(View.VISIBLE);
 
         mFlyout.setCollapsePercent(1f);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index e138595..3557906 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Configuration;
@@ -42,6 +43,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -53,19 +56,20 @@
     @Mock SurfaceControl mRootLeash;
     @Mock DisplayImeController mDisplayImeController;
     @Mock ShellTaskOrganizer mTaskOrganizer;
+    @Captor ArgumentCaptor<Runnable> mRunnableCaptor;
     private SplitLayout mSplitLayout;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mSplitLayout = new SplitLayout(
+        mSplitLayout = spy(new SplitLayout(
                 "TestSplitLayout",
                 mContext,
                 getConfiguration(),
                 mSplitLayoutHandler,
                 b -> b.setParent(mRootLeash),
                 mDisplayImeController,
-                mTaskOrganizer);
+                mTaskOrganizer));
     }
 
     @Test
@@ -92,13 +96,13 @@
     @Test
     public void testUpdateDivideBounds() {
         mSplitLayout.updateDivideBounds(anyInt());
-        verify(mSplitLayoutHandler).onBoundsChanging(any(SplitLayout.class));
+        verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class));
     }
 
     @Test
     public void testSetDividePosition() {
         mSplitLayout.setDividePosition(anyInt());
-        verify(mSplitLayoutHandler).onBoundsChanged(any(SplitLayout.class));
+        verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class));
     }
 
     @Test
@@ -109,18 +113,33 @@
 
     @Test
     @UiThreadTest
-    public void testSnapToDismissTarget() {
+    public void testSnapToDismissStart() {
         // verify it callbacks properly when the snap target indicates dismissing split.
         DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
                 DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
+
         mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
+        waitDividerFlingFinished();
         verify(mSplitLayoutHandler).onSnappedToDismiss(eq(false));
-        snapTarget = getSnapTarget(0 /* position */,
+    }
+
+    @Test
+    @UiThreadTest
+    public void testSnapToDismissEnd() {
+        // verify it callbacks properly when the snap target indicates dismissing split.
+        DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
                 DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
+
         mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
+        waitDividerFlingFinished();
         verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true));
     }
 
+    private void waitDividerFlingFinished() {
+        verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture());
+        mRunnableCaptor.getValue().run();
+    }
+
     private static Configuration getConfiguration() {
         final Configuration configuration = new Configuration();
         configuration.unset();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index ba73d55..1a70f76 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -25,6 +25,7 @@
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
 
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
 import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
@@ -210,15 +211,15 @@
     }
 
     @Test
-    public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets() {
+    public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
         setRunningTask(mFullscreenAppTask);
         mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
         ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+                eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
@@ -227,15 +228,15 @@
     }
 
     @Test
-    public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets() {
+    public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
         setRunningTask(mFullscreenAppTask);
         mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
         ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
+                eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
         reset(mSplitScreenStarter);
 
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
@@ -244,65 +245,55 @@
     }
 
     @Test
-    public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets() {
-        setRunningTask(mNonResizeableFullscreenAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
-        ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
-    }
-
-    @Test
-    public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets() {
-        setRunningTask(mFullscreenAppTask);
-        mPolicy.start(mLandscapeDisplayLayout, mNonResizeableActivityClipData);
-        ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
-
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
-        verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
-    }
-
-    @Test
-    public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() {
+    public void testDragAppOverSplitApp_expectSplitTargets_DropLeft() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
         mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
         ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
-        reset(mSplitScreenStarter);
+                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+    }
 
-        // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+    @Test
+    public void testDragAppOverSplitApp_expectSplitTargets_DropRight() {
+        setInSplitScreen(true);
+        setRunningTask(mSplitPrimaryAppTask);
+        mPolicy.start(mLandscapeDisplayLayout, mActivityClipData);
+        ArrayList<Target> targets = assertExactTargetTypes(
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
+
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
     @Test
-    public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets() {
+    public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropTop() {
         setInSplitScreen(true);
         setRunningTask(mSplitPrimaryAppTask);
         mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
         ArrayList<Target> targets = assertExactTargetTypes(
-                mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
 
-        mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+        mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_UNDEFINED), any());
-        reset(mSplitScreenStarter);
+                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_TOP_OR_LEFT), any());
+    }
 
-        // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+    @Test
+    public void testDragAppOverSplitAppPhone_expectVerticalSplitTargets_DropBottom() {
+        setInSplitScreen(true);
+        setRunningTask(mSplitPrimaryAppTask);
+        mPolicy.start(mPortraitDisplayLayout, mActivityClipData);
+        ArrayList<Target> targets = assertExactTargetTypes(
+                mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
+
         mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
         verify(mSplitScreenStarter).startIntent(any(), any(),
-                eq(STAGE_TYPE_SIDE), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
+                eq(STAGE_TYPE_UNDEFINED), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index a2b1f64..84565e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -20,12 +20,19 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
@@ -48,6 +55,9 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.IDisplayWindowListener;
+import android.view.IWindowManager;
+import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
@@ -65,12 +75,15 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 
@@ -97,8 +110,7 @@
 
     @Test
     public void testBasicTransitionFlow() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         IBinder transitToken = new Binder();
@@ -117,8 +129,7 @@
 
     @Test
     public void testNonDefaultHandler() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
@@ -201,8 +212,7 @@
 
     @Test
     public void testRequestRemoteTransition() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         final boolean[] remoteCalled = new boolean[]{false};
@@ -275,9 +285,28 @@
     }
 
     @Test
+    public void testTransitionFilterNotRequirement() {
+        // filter that requires one opening and NO translucent apps
+        TransitionFilter filter = new TransitionFilter();
+        filter.mRequirements = new TransitionFilter.Requirement[]{
+                new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+        filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+        filter.mRequirements[1].mFlags = FLAG_TRANSLUCENT;
+        filter.mRequirements[1].mNot = true;
+
+        final TransitionInfo openOnly = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).build();
+        assertTrue(filter.matches(openOnly));
+
+        final TransitionInfo openAndTranslucent = new TransitionInfoBuilder(TRANSIT_OPEN)
+                .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+        openAndTranslucent.getChanges().get(1).setFlags(FLAG_TRANSLUCENT);
+        assertFalse(filter.matches(openAndTranslucent));
+    }
+
+    @Test
     public void testRegisteredRemoteTransition() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         final boolean[] remoteCalled = new boolean[]{false};
@@ -322,8 +351,7 @@
 
     @Test
     public void testOneShotRemoteHandler() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         final boolean[] remoteCalled = new boolean[]{false};
@@ -369,8 +397,7 @@
 
     @Test
     public void testTransitionQueueing() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
         IBinder transitToken1 = new Binder();
@@ -410,8 +437,7 @@
 
     @Test
     public void testTransitionMerging() {
-        Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
-                mMainExecutor, mAnimExecutor);
+        Transitions transitions = createTestTransitions();
         mDefaultHandler.setSimulateMerge(true);
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
 
@@ -447,6 +473,63 @@
         assertEquals(0, mDefaultHandler.activeCount());
     }
 
+    @Test
+    public void testShouldRotateSeamlessly() throws Exception {
+        final RunningTaskInfo taskInfo =
+                createTaskInfo(1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final RunningTaskInfo taskInfoPip =
+                createTaskInfo(1, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+
+        final DisplayController displays = createTestDisplayController();
+        final @Surface.Rotation int upsideDown = displays
+                .getDisplayLayout(DEFAULT_DISPLAY).getUpsideDownRotation();
+
+        final TransitionInfo normalDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+                        .build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo).setRotate().build())
+                .build();
+        assertFalse(DefaultTransitionHandler.isRotationSeamless(normalDispRotate, displays));
+
+        // Seamless if all tasks are seamless
+        final TransitionInfo rotateSeamless = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+                        .build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+                .build();
+        assertTrue(DefaultTransitionHandler.isRotationSeamless(rotateSeamless, displays));
+
+        // Not seamless if there is PiP (or any other non-seamless task)
+        final TransitionInfo pipDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+                        .build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfoPip)
+                        .setRotate().build())
+                .build();
+        assertFalse(DefaultTransitionHandler.isRotationSeamless(pipDispRotate, displays));
+
+        // Not seamless if one of rotations is upside-down
+        final TransitionInfo seamlessUpsideDown = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+                        .setRotate(upsideDown, ROTATION_ANIMATION_UNSPECIFIED).build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(upsideDown, ROTATION_ANIMATION_SEAMLESS).build())
+                .build();
+        assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessUpsideDown, displays));
+
+        // Not seamless if system alert windows
+        final TransitionInfo seamlessButAlert = new TransitionInfoBuilder(TRANSIT_CHANGE)
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(
+                        FLAG_IS_DISPLAY | FLAG_DISPLAY_HAS_ALERT_WINDOWS).setRotate().build())
+                .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+                        .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+                .build();
+        assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessButAlert, displays));
+    }
+
     class TransitionInfoBuilder {
         final TransitionInfo mInfo;
 
@@ -469,11 +552,53 @@
             return addChange(mode, null /* taskInfo */);
         }
 
+        TransitionInfoBuilder addChange(TransitionInfo.Change change) {
+            mInfo.addChange(change);
+            return this;
+        }
+
         TransitionInfo build() {
             return mInfo;
         }
     }
 
+    class ChangeBuilder {
+        final TransitionInfo.Change mChange;
+
+        ChangeBuilder(@WindowManager.TransitionType int mode) {
+            mChange = new TransitionInfo.Change(null /* token */, null /* leash */);
+            mChange.setMode(mode);
+        }
+
+        ChangeBuilder setFlags(@TransitionInfo.ChangeFlags int flags) {
+            mChange.setFlags(flags);
+            return this;
+        }
+
+        ChangeBuilder setTask(RunningTaskInfo taskInfo) {
+            mChange.setTaskInfo(taskInfo);
+            return this;
+        }
+
+        ChangeBuilder setRotate(int anim) {
+            return setRotate(Surface.ROTATION_90, anim);
+        }
+
+        ChangeBuilder setRotate() {
+            return setRotate(ROTATION_ANIMATION_UNSPECIFIED);
+        }
+
+        ChangeBuilder setRotate(@Surface.Rotation int target, int anim) {
+            mChange.setRotation(Surface.ROTATION_0, target);
+            mChange.setRotationAnimation(anim);
+            return this;
+        }
+
+        TransitionInfo.Change build() {
+            return mChange;
+        }
+    }
+
     class TestTransitionHandler implements Transitions.TransitionHandler {
         ArrayList<Transitions.TransitionFinishCallback> mFinishes = new ArrayList<>();
         final ArrayList<IBinder> mMerged = new ArrayList<>();
@@ -545,4 +670,45 @@
         return taskInfo;
     }
 
+    private DisplayController createTestDisplayController() {
+        IWindowManager mockWM = mock(IWindowManager.class);
+        final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
+        try {
+            doAnswer(new Answer() {
+                @Override
+                public Object answer(InvocationOnMock invocation) {
+                    displayListener[0] = invocation.getArgument(0);
+                    return null;
+                }
+            }).when(mockWM).registerDisplayWindowListener(any());
+        } catch (RemoteException e) {
+            // No remote stuff happening, so this can't be hit
+        }
+        DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
+        try {
+            displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
+            mMainExecutor.flushAll();
+        } catch (RemoteException e) {
+            // Again, no remote stuff
+        }
+        return out;
+    }
+
+    private Transitions createTestTransitions() {
+        return new Transitions(mOrganizer, mTransactionPool, createTestDisplayController(),
+                mContext, mMainExecutor, mAnimExecutor);
+    }
+//
+//    private class TestDisplayController extends DisplayController {
+//        private final DisplayLayout mTestDisplayLayout;
+//        TestDisplayController() {
+//            super(mContext, mock(IWindowManager.class), mMainExecutor);
+//            mTestDisplayLayout = new DisplayLayout();
+//            mTestDisplayLayout.
+//        }
+//
+//        @Override
+//        DisplayLayout
+//    }
+
 }
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 8d112d1..2b86b1e 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -149,12 +149,14 @@
             android_dataspace dataspace;
             int slot;
             bool newContent = false;
+            ARect currentCrop;
+            uint32_t outTransform;
             // Note: ASurfaceTexture_dequeueBuffer discards all but the last frame. This
             // is necessary if the SurfaceTexture queue is in synchronous mode, and we
             // cannot tell which mode it is in.
             AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer(
-                    mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent,
-                    createReleaseFence, fenceWait, this);
+                    mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &outTransform,
+                    &newContent, createReleaseFence, fenceWait, this, &currentCrop);
 
             if (hardwareBuffer) {
                 mCurrentSlot = slot;
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index fb3e21f..4ec782f 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -27,6 +27,7 @@
 X(ClipRect)
 X(ClipRRect)
 X(ClipRegion)
+X(ResetClip)
 X(DrawPaint)
 X(DrawBehind)
 X(DrawPath)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index c945f27..a285462 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -187,6 +187,11 @@
     SkClipOp op;
     void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); }
 };
+struct ResetClip final : Op {
+    static const auto kType = Type::ResetClip;
+    ResetClip() {}
+    void draw(SkCanvas* c, const SkMatrix&) const { SkAndroidFrameworkUtils::ResetClip(c); }
+};
 
 struct DrawPaint final : Op {
     static const auto kType = Type::DrawPaint;
@@ -662,6 +667,9 @@
 void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) {
     this->push<ClipRegion>(0, region, op);
 }
+void DisplayListData::resetClip() {
+    this->push<ResetClip>(0);
+}
 
 void DisplayListData::drawPaint(const SkPaint& paint) {
     this->push<DrawPaint>(0, paint);
@@ -969,6 +977,14 @@
     fDL->clipRegion(region, op);
     this->INHERITED::onClipRegion(region, op);
 }
+void RecordingCanvas::onResetClip() {
+    // This is part of "replace op" emulation, but rely on the following intersection
+    // clip to potentially mark the clip as complex. If we are already complex, we do
+    // not reset the complexity so that we don't break the contract that no higher
+    // save point has a complex clip when "not complex".
+    fDL->resetClip();
+    this->INHERITED::onResetClip();
+}
 
 void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
     fDL->drawPaint(paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 4fae6a1..212b4e7 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -97,6 +97,7 @@
     void clipRect(const SkRect&, SkClipOp, bool aa);
     void clipRRect(const SkRRect&, SkClipOp, bool aa);
     void clipRegion(const SkRegion&, SkClipOp);
+    void resetClip();
 
     void drawPaint(const SkPaint&);
     void drawBehind(const SkPaint&);
@@ -169,6 +170,7 @@
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
     void onClipRegion(const SkRegion&, SkClipOp) override;
+    void onResetClip() override;
 
     void onDrawPaint(const SkPaint&) override;
     void onDrawBehind(const SkPaint&) override;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index d6b6e16..53c6db0 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -396,6 +396,22 @@
     return !mCanvas->isClipEmpty();
 }
 
+bool SkiaCanvas::replaceClipRect_deprecated(float left, float top, float right, float bottom) {
+    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+
+    // Emulated clip rects are not recorded for partial saves, since
+    // partial saves have been removed from the public API.
+    SkAndroidFrameworkUtils::ResetClip(mCanvas);
+    mCanvas->clipRect(rect, SkClipOp::kIntersect);
+    return !mCanvas->isClipEmpty();
+}
+
+bool SkiaCanvas::replaceClipPath_deprecated(const SkPath* path) {
+    SkAndroidFrameworkUtils::ResetClip(mCanvas);
+    mCanvas->clipPath(*path, SkClipOp::kIntersect, true);
+    return !mCanvas->isClipEmpty();
+}
+
 // ----------------------------------------------------------------------------
 // Canvas state operations: Filters
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index fd6bbdc..715007c 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -26,6 +26,7 @@
 #include "hwui/BlurDrawLooper.h"
 
 #include <SkCanvas.h>
+#include <SkDeque.h>
 #include "pipeline/skia/AnimatedDrawables.h"
 #include "src/core/SkArenaAlloc.h"
 
@@ -93,6 +94,9 @@
     virtual bool quickRejectPath(const SkPath& path) const override;
     virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override;
     virtual bool clipPath(const SkPath* path, SkClipOp op) override;
+    virtual bool replaceClipRect_deprecated(float left, float top, float right,
+                                            float bottom) override;
+    virtual bool replaceClipPath_deprecated(const SkPath* path) override;
 
     virtual PaintFilter* getPaintFilter() override;
     virtual void setPaintFilter(sk_sp<PaintFilter> paintFilter) override;
diff --git a/libs/hwui/canvas/CanvasFrontend.cpp b/libs/hwui/canvas/CanvasFrontend.cpp
index 8f261c83..dd01a5b 100644
--- a/libs/hwui/canvas/CanvasFrontend.cpp
+++ b/libs/hwui/canvas/CanvasFrontend.cpp
@@ -54,13 +54,10 @@
     return false;
 }
 
-// Assert that the cast from SkClipOp to SkRegion::Op is valid
+// Assert that the cast from SkClipOp to SkRegion::Op is valid.
+// SkClipOp is a subset of SkRegion::Op and only supports difference and intersect.
 static_assert(static_cast<int>(SkClipOp::kDifference) == SkRegion::Op::kDifference_Op);
 static_assert(static_cast<int>(SkClipOp::kIntersect) == SkRegion::Op::kIntersect_Op);
-static_assert(static_cast<int>(SkClipOp::kUnion_deprecated) == SkRegion::Op::kUnion_Op);
-static_assert(static_cast<int>(SkClipOp::kXOR_deprecated) == SkRegion::Op::kXOR_Op);
-static_assert(static_cast<int>(SkClipOp::kReverseDifference_deprecated) == SkRegion::Op::kReverseDifference_Op);
-static_assert(static_cast<int>(SkClipOp::kReplace_deprecated) == SkRegion::Op::kReplace_Op);
 
 void CanvasStateHelper::internalClipRect(const SkRect& rect, SkClipOp op) {
     clip().opRect(rect, transform(), mInitialBounds, (SkRegion::Op)op, false);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 70a558b..8277764 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -185,6 +185,12 @@
 
     virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) = 0;
     virtual bool clipPath(const SkPath* path, SkClipOp op) = 0;
+    // Resets clip to wide open, used to emulate the now-removed SkClipOp::kReplace on
+    // apps with compatibility < P. Canvases for version P and later are restricted to
+    // intersect and difference at the Java level, matching SkClipOp's definition.
+    // NOTE: These functions are deprecated and will be removed in a future release
+    virtual bool replaceClipRect_deprecated(float left, float top, float right, float bottom) = 0;
+    virtual bool replaceClipPath_deprecated(const SkPath* path) = 0;
 
     // filters
     virtual PaintFilter* getPaintFilter() = 0;
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index c9433ec8..c40b858 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -30,7 +30,8 @@
 
 using namespace android;
 
-static jmethodID gAnimatedImageDrawable_onAnimationEndMethodID;
+static jclass gAnimatedImageDrawableClass;
+static jmethodID gAnimatedImageDrawable_callOnAnimationEndMethodID;
 
 // Note: jpostProcess holds a handle to the ImageDecoder.
 static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -178,26 +179,23 @@
 public:
     InvokeListener(JNIEnv* env, jobject javaObject) {
         LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
-        // Hold a weak reference to break a cycle that would prevent GC.
-        mWeakRef = env->NewWeakGlobalRef(javaObject);
+        mCallbackRef = env->NewGlobalRef(javaObject);
     }
 
     ~InvokeListener() override {
         auto* env = requireEnv(mJvm);
-        env->DeleteWeakGlobalRef(mWeakRef);
+        env->DeleteGlobalRef(mCallbackRef);
     }
 
     virtual void handleMessage(const Message&) override {
         auto* env = get_env_or_die(mJvm);
-        jobject localRef = env->NewLocalRef(mWeakRef);
-        if (localRef) {
-            env->CallVoidMethod(localRef, gAnimatedImageDrawable_onAnimationEndMethodID);
-        }
+        env->CallStaticVoidMethod(gAnimatedImageDrawableClass,
+                                  gAnimatedImageDrawable_callOnAnimationEndMethodID, mCallbackRef);
     }
 
 private:
     JavaVM* mJvm;
-    jweak mWeakRef;
+    jobject mCallbackRef;
 };
 
 class JniAnimationEndListener : public OnAnimationEndListener {
@@ -253,26 +251,31 @@
 }
 
 static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
-    { "nCreate",             "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",(void*) AnimatedImageDrawable_nCreate },
-    { "nGetNativeFinalizer", "()J",                                                          (void*) AnimatedImageDrawable_nGetNativeFinalizer },
-    { "nDraw",               "(JJ)J",                                                        (void*) AnimatedImageDrawable_nDraw },
-    { "nSetAlpha",           "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetAlpha },
-    { "nGetAlpha",           "(J)I",                                                         (void*) AnimatedImageDrawable_nGetAlpha },
-    { "nSetColorFilter",     "(JJ)V",                                                        (void*) AnimatedImageDrawable_nSetColorFilter },
-    { "nIsRunning",          "(J)Z",                                                         (void*) AnimatedImageDrawable_nIsRunning },
-    { "nStart",              "(J)Z",                                                         (void*) AnimatedImageDrawable_nStart },
-    { "nStop",               "(J)Z",                                                         (void*) AnimatedImageDrawable_nStop },
-    { "nGetRepeatCount",     "(J)I",                                                         (void*) AnimatedImageDrawable_nGetRepeatCount },
-    { "nSetRepeatCount",     "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetRepeatCount },
-    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
-    { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
-    { "nSetMirrored",        "(JZ)V",                                                        (void*) AnimatedImageDrawable_nSetMirrored },
-    { "nSetBounds",          "(JLandroid/graphics/Rect;)V",                                  (void*) AnimatedImageDrawable_nSetBounds },
+        {"nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",
+         (void*)AnimatedImageDrawable_nCreate},
+        {"nGetNativeFinalizer", "()J", (void*)AnimatedImageDrawable_nGetNativeFinalizer},
+        {"nDraw", "(JJ)J", (void*)AnimatedImageDrawable_nDraw},
+        {"nSetAlpha", "(JI)V", (void*)AnimatedImageDrawable_nSetAlpha},
+        {"nGetAlpha", "(J)I", (void*)AnimatedImageDrawable_nGetAlpha},
+        {"nSetColorFilter", "(JJ)V", (void*)AnimatedImageDrawable_nSetColorFilter},
+        {"nIsRunning", "(J)Z", (void*)AnimatedImageDrawable_nIsRunning},
+        {"nStart", "(J)Z", (void*)AnimatedImageDrawable_nStart},
+        {"nStop", "(J)Z", (void*)AnimatedImageDrawable_nStop},
+        {"nGetRepeatCount", "(J)I", (void*)AnimatedImageDrawable_nGetRepeatCount},
+        {"nSetRepeatCount", "(JI)V", (void*)AnimatedImageDrawable_nSetRepeatCount},
+        {"nSetOnAnimationEndListener", "(JLjava/lang/ref/WeakReference;)V",
+         (void*)AnimatedImageDrawable_nSetOnAnimationEndListener},
+        {"nNativeByteSize", "(J)J", (void*)AnimatedImageDrawable_nNativeByteSize},
+        {"nSetMirrored", "(JZ)V", (void*)AnimatedImageDrawable_nSetMirrored},
+        {"nSetBounds", "(JLandroid/graphics/Rect;)V", (void*)AnimatedImageDrawable_nSetBounds},
 };
 
 int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
-    jclass animatedImageDrawable_class = FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable");
-    gAnimatedImageDrawable_onAnimationEndMethodID = GetMethodIDOrDie(env, animatedImageDrawable_class, "onAnimationEnd", "()V");
+    gAnimatedImageDrawableClass = reinterpret_cast<jclass>(env->NewGlobalRef(
+            FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable")));
+    gAnimatedImageDrawable_callOnAnimationEndMethodID =
+            GetStaticMethodIDOrDie(env, gAnimatedImageDrawableClass, "callOnAnimationEnd",
+                                   "(Ljava/lang/ref/WeakReference;)V");
 
     return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
             gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
diff --git a/libs/hwui/jni/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index 6942017..b7ddd21 100644
--- a/libs/hwui/jni/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -64,7 +64,7 @@
     }
 
     static jlong validateNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) {
-        size_t chunkSize = env->GetArrayLength(obj);
+        size_t chunkSize = obj != NULL ? env->GetArrayLength(obj) : 0;
         if (chunkSize < (int) (sizeof(Res_png_9patch))) {
             jniThrowRuntimeException(env, "Array too small for chunk.");
             return NULL;
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index a4cf028..0ef80ee 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -188,14 +188,10 @@
     return result ? JNI_TRUE : JNI_FALSE;
 }
 
-// SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
-// from one to the other (though SkClipOp is destined to become a strict subset)
+// SkClipOp is a strict subset of SkRegion::Op and is castable back and forth for their
+// shared operations (intersect and difference).
 static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
 static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
-static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion_deprecated), "");
-static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR_deprecated), "");
-static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
-static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");
 
 static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
                          jfloat r, jfloat b, jint opHandle) {
@@ -203,16 +199,16 @@
     SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
     bool nonEmptyClip;
     switch (rgnOp) {
-        case SkRegion::Op::kReplace_Op:
-            // For now replace can still be handled as an SkClipOp but will be emulated in the
-            // future
-            [[fallthrough]];
         case SkRegion::Op::kIntersect_Op:
         case SkRegion::Op::kDifference_Op:
             // Intersect and difference are supported clip operations
             nonEmptyClip =
                     get_canvas(canvasHandle)->clipRect(l, t, r, b, static_cast<SkClipOp>(rgnOp));
             break;
+        case SkRegion::Op::kReplace_Op:
+            // Replace is emulated to support legacy apps older than P
+            nonEmptyClip = get_canvas(canvasHandle)->replaceClipRect_deprecated(l, t, r, b);
+            break;
         default:
             // All other operations would expand the clip and are no longer supported,
             // so log and skip (to avoid breaking legacy apps).
@@ -230,14 +226,13 @@
     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
     bool nonEmptyClip;
     switch (rgnOp) {
-        case SkRegion::Op::kReplace_Op:
-            // For now replace can still be handled as an SkClipOp but will be emulated in the
-            // future
-            [[fallthrough]];
         case SkRegion::Op::kIntersect_Op:
         case SkRegion::Op::kDifference_Op:
             nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, static_cast<SkClipOp>(rgnOp));
             break;
+        case SkRegion::Op::kReplace_Op:
+            nonEmptyClip = get_canvas(canvasHandle)->replaceClipPath_deprecated(path);
+            break;
         default:
             ALOGW("Ignoring unsupported clip operation %d", opHandle);
             SkRect clipBounds;  // ignored
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index e1da169..944393c 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -547,9 +547,12 @@
 // SurfaceView position callback
 // ----------------------------------------------------------------------------
 
-jmethodID gPositionListener_PositionChangedMethod;
-jmethodID gPositionListener_ApplyStretchMethod;
-jmethodID gPositionListener_PositionLostMethod;
+struct {
+    jclass clazz;
+    jmethodID callPositionChanged;
+    jmethodID callApplyStretch;
+    jmethodID callPositionLost;
+} gPositionListener;
 
 static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
         jlong renderNodePtr, jobject listener) {
@@ -557,16 +560,16 @@
     public:
         PositionListenerTrampoline(JNIEnv* env, jobject listener) {
             env->GetJavaVM(&mVm);
-            mWeakRef = env->NewWeakGlobalRef(listener);
+            mListener = env->NewGlobalRef(listener);
         }
 
         virtual ~PositionListenerTrampoline() {
-            jnienv()->DeleteWeakGlobalRef(mWeakRef);
-            mWeakRef = nullptr;
+            jnienv()->DeleteGlobalRef(mListener);
+            mListener = nullptr;
         }
 
         virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
-            if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
+            if (CC_UNLIKELY(!mListener || !info.updateWindowPositions)) return;
 
             Matrix4 transform;
             info.damageAccumulator->computeCurrentTransform(&transform);
@@ -609,7 +612,7 @@
         }
 
         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
-            if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
+            if (CC_UNLIKELY(!mListener || (info && !info->updateWindowPositions))) return;
 
             if (mPreviousPosition.isEmpty()) {
                 return;
@@ -618,18 +621,16 @@
 
             ATRACE_NAME("SurfaceView position lost");
             JNIEnv* env = jnienv();
-            jobject localref = env->NewLocalRef(mWeakRef);
-            if (CC_UNLIKELY(!localref)) {
-                env->DeleteWeakGlobalRef(mWeakRef);
-                mWeakRef = nullptr;
-                return;
-            }
 #ifdef __ANDROID__ // Layoutlib does not support CanvasContext
             // TODO: Remember why this is synchronous and then make a comment
-            env->CallVoidMethod(localref, gPositionListener_PositionLostMethod,
+            jboolean keepListening = env->CallStaticBooleanMethod(
+                    gPositionListener.clazz, gPositionListener.callPositionLost, mListener,
                     info ? info->canvasContext.getFrameNumber() : 0);
+            if (!keepListening) {
+                env->DeleteGlobalRef(mListener);
+                mListener = nullptr;
+            }
 #endif
-            env->DeleteLocalRef(localref);
         }
 
     private:
@@ -684,28 +685,20 @@
                 StretchEffectBehavior::Shader) {
                 JNIEnv* env = jnienv();
 
-                jobject localref = env->NewLocalRef(mWeakRef);
-                if (CC_UNLIKELY(!localref)) {
-                    env->DeleteWeakGlobalRef(mWeakRef);
-                    mWeakRef = nullptr;
-                    return;
-                }
 #ifdef __ANDROID__  // Layoutlib does not support CanvasContext
                 SkVector stretchDirection = effect->getStretchDirection();
-                env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
-                                    info.canvasContext.getFrameNumber(),
-                                    result.width,
-                                    result.height,
-                                    stretchDirection.fX,
-                                    stretchDirection.fY,
-                                    effect->maxStretchAmountX,
-                                    effect->maxStretchAmountY,
-                                    childRelativeBounds.left(),
-                                    childRelativeBounds.top(),
-                                    childRelativeBounds.right(),
-                                    childRelativeBounds.bottom());
+                jboolean keepListening = env->CallStaticBooleanMethod(
+                        gPositionListener.clazz, gPositionListener.callApplyStretch, mListener,
+                        info.canvasContext.getFrameNumber(), result.width, result.height,
+                        stretchDirection.fX, stretchDirection.fY, effect->maxStretchAmountX,
+                        effect->maxStretchAmountY, childRelativeBounds.left(),
+                        childRelativeBounds.top(), childRelativeBounds.right(),
+                        childRelativeBounds.bottom());
+                if (!keepListening) {
+                    env->DeleteGlobalRef(mListener);
+                    mListener = nullptr;
+                }
 #endif
-                env->DeleteLocalRef(localref);
             }
         }
 
@@ -714,14 +707,12 @@
             ATRACE_NAME("Update SurfaceView position");
 
             JNIEnv* env = jnienv();
-            jobject localref = env->NewLocalRef(mWeakRef);
-            if (CC_UNLIKELY(!localref)) {
-                env->DeleteWeakGlobalRef(mWeakRef);
-                mWeakRef = nullptr;
-            } else {
-                env->CallVoidMethod(localref, gPositionListener_PositionChangedMethod,
-                        frameNumber, left, top, right, bottom);
-                env->DeleteLocalRef(localref);
+            jboolean keepListening = env->CallStaticBooleanMethod(
+                    gPositionListener.clazz, gPositionListener.callPositionChanged, mListener,
+                    frameNumber, left, top, right, bottom);
+            if (!keepListening) {
+                env->DeleteGlobalRef(mListener);
+                mListener = nullptr;
             }
 
             // We need to release ourselves here
@@ -729,7 +720,7 @@
         }
 
         JavaVM* mVm;
-        jobject mWeakRef;
+        jobject mListener;
         uirenderer::Rect mPreviousPosition;
     };
 
@@ -754,7 +745,7 @@
         {"nGetAllocatedSize", "(J)I", (void*)android_view_RenderNode_getAllocatedSize},
         {"nAddAnimator", "(JJ)V", (void*)android_view_RenderNode_addAnimator},
         {"nEndAllAnimators", "(J)V", (void*)android_view_RenderNode_endAllAnimators},
-        {"nRequestPositionUpdates", "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V",
+        {"nRequestPositionUpdates", "(JLjava/lang/ref/WeakReference;)V",
          (void*)android_view_RenderNode_requestPositionUpdates},
 
         // ----------------------------------------------------------------------------
@@ -852,12 +843,13 @@
 
 int register_android_view_RenderNode(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/graphics/RenderNode$PositionUpdateListener");
-    gPositionListener_PositionChangedMethod = GetMethodIDOrDie(env, clazz,
-            "positionChanged", "(JIIII)V");
-    gPositionListener_ApplyStretchMethod =
-            GetMethodIDOrDie(env, clazz, "applyStretch", "(JFFFFFFFFFF)V");
-    gPositionListener_PositionLostMethod = GetMethodIDOrDie(env, clazz,
-            "positionLost", "(J)V");
+    gPositionListener.clazz = MakeGlobalRefOrDie(env, clazz);
+    gPositionListener.callPositionChanged = GetStaticMethodIDOrDie(
+            env, clazz, "callPositionChanged", "(Ljava/lang/ref/WeakReference;JIIII)Z");
+    gPositionListener.callApplyStretch = GetStaticMethodIDOrDie(
+            env, clazz, "callApplyStretch", "(Ljava/lang/ref/WeakReference;JFFFFFFFFFF)Z");
+    gPositionListener.callPositionLost = GetStaticMethodIDOrDie(
+            env, clazz, "callPositionLost", "(Ljava/lang/ref/WeakReference;J)Z");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 3580bed..3f89c07 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -52,6 +52,8 @@
         mOutput << mIdent << "clipRegion" << std::endl;
     }
 
+    void onResetClip() override { mOutput << mIdent << "resetClip" << std::endl; }
+
     void onDrawPaint(const SkPaint&) override { mOutput << mIdent << "drawPaint" << std::endl; }
 
     void onDrawPath(const SkPath&, const SkPaint&) override {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ab9d0b2..bb0b135 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -483,6 +483,12 @@
     if (!Properties::isDrawingEnabled() ||
         (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+        if (auto grContext = getGrContext()) {
+            // Submit to ensure that any texture uploads complete and Skia can
+            // free its staging buffers.
+            grContext->flushAndSubmit();
+        }
+
         // Notify the callbacks, even if there's nothing to draw so they aren't waiting
         // indefinitely
         waitOnFences();
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 8c999c4..57a7fe3 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -382,7 +382,7 @@
     std::vector<sp<RenderNode>> nodes;
     nodes.push_back(TestUtils::createSkiaNode(
             20, 20, 30, 30, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
-                canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
+                canvas.replaceClipRect_deprecated(0, -20, 10, 30);
                 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
             }));
 
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index c827932..cb887f2 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -38,6 +38,17 @@
 
     public abstract void updateRingerModeAffectedStreamsInternal();
 
+    /**
+     * Notify the UID of the currently active {@link android.service.voice.HotwordDetectionService}.
+     *
+     * <p>The caller is expected to take care of any performance implications, e.g. by using a
+     * background thread to call this method.</p>
+     *
+     * @param uid UID of the currently active service or {@link android.os.Process#INVALID_UID} if
+     *            none.
+     */
+    public abstract void setHotwordDetectionServiceUid(int uid);
+
     public abstract void setAccessibilityServiceUids(IntArray uids);
 
     /**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 321db4e..5bd6891 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1769,6 +1769,13 @@
     public static native int setAssistantUid(int uid);
 
     /**
+     * Communicate UID of the current {@link android.service.voice.HotwordDetectionService} to audio
+     * policy service.
+     * @hide
+     */
+    public static native int setHotwordDetectionServiceUid(int uid);
+
+    /**
      * @hide
      * Communicate UIDs of active accessibility services to audio policy service.
      */
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 41e443f..115fb74 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1568,6 +1568,9 @@
             if (isFdDuped) {
                 closeFileDescriptor(fileDescriptor);
             }
+            if (modernFd != null) {
+                modernFd.close();
+            }
         }
     }
 
@@ -2557,17 +2560,13 @@
 
     private void initForFilename(String filename) throws IOException {
         FileInputStream in = null;
+        ParcelFileDescriptor modernFd = null;
         mAssetInputStream = null;
         mFilename = filename;
         mIsInputStream = false;
         try {
             in = new FileInputStream(filename);
-            ParcelFileDescriptor modernFd;
-            try {
-                modernFd = FileUtils.convertToModernFd(in.getFD());
-            } catch (IOException e) {
-                modernFd = null;
-            }
+            modernFd = FileUtils.convertToModernFd(in.getFD());
             if (modernFd != null) {
                 closeQuietly(in);
                 in = new FileInputStream(modernFd.getFileDescriptor());
@@ -2578,6 +2577,9 @@
             loadAttributes(in);
         } finally {
             closeQuietly(in);
+            if (modernFd != null) {
+                modernFd.close();
+            }
         }
     }
 
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 2943eee..a15529e 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -36,6 +36,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.SystemProperties;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -52,6 +53,8 @@
  * frame and meta data from an input media file.
  */
 public class MediaMetadataRetriever implements AutoCloseable {
+    private static final String TAG = "MediaMetadataRetriever";
+
     // borrowed from ExoPlayer
     private static final String[] STANDARD_GENRES = new String[] {
             // These are the official ID3v1 genres.
@@ -301,11 +304,15 @@
      */
     public void setDataSource(FileDescriptor fd, long offset, long length)
             throws IllegalArgumentException  {
-        ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
-        if (modernFd == null) {
-            _setDataSource(fd, offset, length);
-        } else {
-            _setDataSource(modernFd.getFileDescriptor(), offset, length);
+
+        try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+            if (modernFd == null) {
+                _setDataSource(fd, offset, length);
+            } else {
+                _setDataSource(modernFd.getFileDescriptor(), offset, length);
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Ignoring IO error while setting data source", e);
         }
     }
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ccd830a..83bc38b2 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1270,11 +1270,14 @@
      */
     public void setDataSource(FileDescriptor fd, long offset, long length)
             throws IOException, IllegalArgumentException, IllegalStateException {
-        ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
-        if (modernFd == null) {
-            _setDataSource(fd, offset, length);
-        } else {
-            _setDataSource(modernFd.getFileDescriptor(), offset, length);
+        try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+            if (modernFd == null) {
+                _setDataSource(fd, offset, length);
+            } else {
+                _setDataSource(modernFd.getFileDescriptor(), offset, length);
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Ignoring IO error while setting data source", e);
         }
     }
 
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 628f7ee..7f7fb60 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -292,8 +292,7 @@
         }
         synchronized (mRoutesLock) {
             for (MediaRoute2Info route : mRoutes.values()) {
-                if (sessionInfo.getSelectedRoutes().contains(route.getId())
-                        || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+                if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
                     routes.add(route);
                     continue;
                 }
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index d00e5b5..fbd2d8d 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -420,6 +420,20 @@
                     rate = 44100;
                 }
                 mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
+            } else {
+                // Ensure that 'mFormat' uses an output channel mask. Using an input channel
+                // mask was not made 'illegal' initially, however the framework code
+                // assumes usage in AudioMixes of output channel masks only (b/194910301).
+                if ((mFormat.getPropertySetMask()
+                                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0) {
+                    if (mFormat.getChannelCount() == 1
+                            && mFormat.getChannelMask() == AudioFormat.CHANNEL_IN_MONO) {
+                        mFormat = new AudioFormat.Builder(mFormat).setChannelMask(
+                                AudioFormat.CHANNEL_OUT_MONO).build();
+                    }
+                    // CHANNEL_IN_STEREO == CHANNEL_OUT_STEREO so no need to correct.
+                    // CHANNEL_IN_FRONT_BACK is hidden, should not appear.
+                }
             }
             if ((mDeviceSystemType != AudioSystem.DEVICE_NONE)
                     && (mDeviceSystemType != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 37e1415..72cddc9 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -16,14 +16,14 @@
 
 package android.media.projection;
 
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
-import android.media.projection.IMediaProjection;
-import android.media.projection.IMediaProjectionCallback;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.ArrayMap;
@@ -106,7 +106,7 @@
         if (isSecure) {
             flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
         }
-        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
                 height, dpi);
         builder.setFlags(flags);
         if (surface != null) {
@@ -141,7 +141,7 @@
     public VirtualDisplay createVirtualDisplay(@NonNull String name,
             int width, int height, int dpi, int flags, @Nullable Surface surface,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
-        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
                 height, dpi);
         builder.setFlags(flags);
         if (surface != null) {
@@ -151,6 +151,26 @@
     }
 
     /**
+     * Constructs a {@link VirtualDisplayConfig.Builder}, which will mirror the contents of a
+     * DisplayArea. The DisplayArea to mirror is from the DisplayArea the caller is launched on.
+     *
+     * @param name   The name of the virtual display, must be non-empty.
+     * @param width  The width of the virtual display in pixels. Must be greater than 0.
+     * @param height The height of the virtual display in pixels. Must be greater than 0.
+     * @param dpi    The density of the virtual display in dpi. Must be greater than 0.
+     * @return a config representing a VirtualDisplay
+     */
+    private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
+            int width, int height, int dpi) {
+        Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                TYPE_APPLICATION, null /* options */);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+                height, dpi);
+        builder.setWindowTokenClientToMirror(windowContext.getWindowContextToken());
+        return builder;
+    }
+
+    /**
      * Creates a {@link android.hardware.display.VirtualDisplay} to capture the
      * contents of the screen.
      *
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 3b0f577..7c750ce 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -39,8 +39,8 @@
     ISession createSession(String packageName, in ISessionCallback sessionCb, String tag,
             in Bundle sessionInfo, int userId);
     List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
-    MediaSession.Token getMediaKeyEventSession();
-    String getMediaKeyEventSessionPackageName();
+    MediaSession.Token getMediaKeyEventSession(in ComponentName compName);
+    String getMediaKeyEventSessionPackageName(in ComponentName compName);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
     boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
@@ -66,7 +66,8 @@
     void addOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
     void removeOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener);
     void addOnMediaKeyEventSessionChangedListener(
-            in IOnMediaKeyEventSessionChangedListener listener);
+            in IOnMediaKeyEventSessionChangedListener listener,
+            in ComponentName notificationListener);
     void removeOnMediaKeyEventSessionChangedListener(
             in IOnMediaKeyEventSessionChangedListener listener);
     void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 269b70b..8e731a5 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -205,7 +205,28 @@
     @Nullable
     public MediaSession.Token getMediaKeyEventSession() {
         try {
-            return mService.getMediaKeyEventSession();
+            return mService.getMediaKeyEventSession(null);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to get media key event session", ex);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the media key event session, which would receive a media key event unless specified.
+     * <p>
+     * This requires that your app is an enabled notificationlistener using the
+     * {@link NotificationListenerService} APIs, in which case you must pass
+     * the {@link ComponentName} of your enabled listener.
+     *
+     * @return The media key event session, which would receive key events by default, unless
+     *          the caller has specified the target. Can be {@code null}.
+     */
+    @Nullable
+    public MediaSession.Token getMediaKeyEventSession(@NonNull ComponentName notificationListener) {
+        Objects.requireNonNull(notificationListener, "notificationListener shouldn't be null");
+        try {
+            return mService.getMediaKeyEventSession(notificationListener);
         } catch (RemoteException ex) {
             Log.e(TAG, "Failed to get media key event session", ex);
         }
@@ -224,10 +245,34 @@
     @NonNull
     public String getMediaKeyEventSessionPackageName() {
         try {
-            String packageName = mService.getMediaKeyEventSessionPackageName();
+            String packageName = mService.getMediaKeyEventSessionPackageName(null);
             return (packageName != null) ? packageName : "";
         } catch (RemoteException ex) {
-            Log.e(TAG, "Failed to get media key event session", ex);
+            Log.e(TAG, "Failed to get media key event session package name", ex);
+        }
+        return "";
+    }
+
+    /**
+     * Gets the package name of the media key event session.
+     * <p>
+     * This requires that your app is an enabled notificationlistener using the
+     * {@link NotificationListenerService} APIs, in which case you must pass
+     * the {@link ComponentName} of your enabled listener.
+     *
+     * @return The package name of the media key event session or the last session's media button
+     *          receiver if the media key event session is {@code null}. Returns an empty string
+     *          if neither of them exists.
+     * @see #getMediaKeyEventSession(ComponentName)
+     */
+    @NonNull
+    public String getMediaKeyEventSessionPackageName(@NonNull ComponentName notificationListener) {
+        Objects.requireNonNull(notificationListener, "notificationListener shouldn't be null");
+        try {
+            String packageName = mService.getMediaKeyEventSessionPackageName(notificationListener);
+            return (packageName != null) ? packageName : "";
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to get media key event session package name", ex);
         }
         return "";
     }
@@ -905,44 +950,67 @@
     public void addOnMediaKeyEventSessionChangedListener(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnMediaKeyEventSessionChangedListener listener) {
+        addOnMediaKeyEventSessionChangedListenerInternal(null, executor, listener);
+    }
+
+    /**
+     * Add a listener to be notified when the media key session is changed.
+     * <p>
+     * This requires that your app is an enabled notificationlistener using the
+     * {@link NotificationListenerService} APIs, in which case you must pass
+     * the {@link ComponentName} of your enabled listener.
+     *
+     * @param notificationListener The enabled notification listener component.
+     * @param executor The executor on which the listener should be invoked.
+     * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
+     */
+    public void addOnMediaKeyEventSessionChangedListener(
+            @NonNull ComponentName notificationListener,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnMediaKeyEventSessionChangedListener listener) {
+        Objects.requireNonNull(notificationListener, "notificationListener shouldn't be null");
+        addOnMediaKeyEventSessionChangedListenerInternal(notificationListener, executor, listener);
+    }
+
+    private void addOnMediaKeyEventSessionChangedListenerInternal(
+            @Nullable ComponentName notificationListener,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnMediaKeyEventSessionChangedListener listener) {
         Objects.requireNonNull(executor, "executor shouldn't be null");
         Objects.requireNonNull(listener, "listener shouldn't be null");
         synchronized (mLock) {
             try {
+                if (mMediaKeyEventSessionChangedCallbacks.isEmpty()) {
+                    mService.addOnMediaKeyEventSessionChangedListener(
+                            mOnMediaKeyEventSessionChangedListenerStub, notificationListener);
+                }
                 mMediaKeyEventSessionChangedCallbacks.put(listener, executor);
                 executor.execute(
                         () -> listener.onMediaKeyEventSessionChanged(
                                 mCurMediaKeyEventSessionPackage, mCurMediaKeyEventSession));
-                if (mMediaKeyEventSessionChangedCallbacks.size() == 1) {
-                    mService.addOnMediaKeyEventSessionChangedListener(
-                            mOnMediaKeyEventSessionChangedListenerStub);
-                }
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to set media key listener", e);
+                Log.e(TAG, "Failed to add MediaKeyEventSessionChangedListener", e);
             }
         }
     }
 
     /**
-     * Remove a {@link OnMediaKeyEventSessionChangedListener}.
+     * Stop receiving updates on media key event session change on the specified listener.
      *
      * @param listener A {@link OnMediaKeyEventSessionChangedListener}.
-     * @hide
      */
-    @SystemApi
-    @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
     public void removeOnMediaKeyEventSessionChangedListener(
             @NonNull OnMediaKeyEventSessionChangedListener listener) {
         Objects.requireNonNull(listener, "listener shouldn't be null");
         synchronized (mLock) {
             try {
-                mMediaKeyEventSessionChangedCallbacks.remove(listener);
-                if (mMediaKeyEventSessionChangedCallbacks.size() == 0) {
+                if (mMediaKeyEventSessionChangedCallbacks.remove(listener) != null
+                        && mMediaKeyEventSessionChangedCallbacks.isEmpty()) {
                     mService.removeOnMediaKeyEventSessionChangedListener(
                             mOnMediaKeyEventSessionChangedListenerStub);
                 }
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to set media key listener", e);
+                Log.e(TAG, "Failed to remove MediaKeyEventSessionChangedListener", e);
             }
         }
     }
@@ -1124,16 +1192,14 @@
     /**
      * Listener to receive changes in the media key event session, which would receive a media key
      * event unless specified.
-     * @hide
      */
-    @SystemApi
     public interface OnMediaKeyEventSessionChangedListener {
         /**
          * Called when the media key session is changed to the given media session. The key event
          * session is the media session which would receive key event by default, unless the caller
          * has specified the target.
          * <p>
-         * The session token can be {@link null} if the media button session is unset. In that case,
+         * The session token can be {@code null} if the media button session is unset. In that case,
          * packageName will return the package name of the last session's media button receiver, or
          * an empty string if the last session didn't set a media button receiver.
          *
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 8b69d33..6a6a22c 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -20,7 +20,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.LnbEventType;
+import android.hardware.tv.tuner.LnbPosition;
+import android.hardware.tv.tuner.LnbTone;
+import android.hardware.tv.tuner.LnbVoltage;
 import android.media.tv.tuner.Tuner.Result;
 
 import java.lang.annotation.Retention;
@@ -48,39 +51,39 @@
     /**
      * LNB power voltage not set.
      */
-    public static final int VOLTAGE_NONE = Constants.LnbVoltage.NONE;
+    public static final int VOLTAGE_NONE = LnbVoltage.NONE;
     /**
      * LNB power voltage 5V.
      */
-    public static final int VOLTAGE_5V = Constants.LnbVoltage.VOLTAGE_5V;
+    public static final int VOLTAGE_5V = LnbVoltage.VOLTAGE_5V;
     /**
      * LNB power voltage 11V.
      */
-    public static final int VOLTAGE_11V = Constants.LnbVoltage.VOLTAGE_11V;
+    public static final int VOLTAGE_11V = LnbVoltage.VOLTAGE_11V;
     /**
      * LNB power voltage 12V.
      */
-    public static final int VOLTAGE_12V = Constants.LnbVoltage.VOLTAGE_12V;
+    public static final int VOLTAGE_12V = LnbVoltage.VOLTAGE_12V;
     /**
      * LNB power voltage 13V.
      */
-    public static final int VOLTAGE_13V = Constants.LnbVoltage.VOLTAGE_13V;
+    public static final int VOLTAGE_13V = LnbVoltage.VOLTAGE_13V;
     /**
      * LNB power voltage 14V.
      */
-    public static final int VOLTAGE_14V = Constants.LnbVoltage.VOLTAGE_14V;
+    public static final int VOLTAGE_14V = LnbVoltage.VOLTAGE_14V;
     /**
      * LNB power voltage 15V.
      */
-    public static final int VOLTAGE_15V = Constants.LnbVoltage.VOLTAGE_15V;
+    public static final int VOLTAGE_15V = LnbVoltage.VOLTAGE_15V;
     /**
      * LNB power voltage 18V.
      */
-    public static final int VOLTAGE_18V = Constants.LnbVoltage.VOLTAGE_18V;
+    public static final int VOLTAGE_18V = LnbVoltage.VOLTAGE_18V;
     /**
      * LNB power voltage 19V.
      */
-    public static final int VOLTAGE_19V = Constants.LnbVoltage.VOLTAGE_19V;
+    public static final int VOLTAGE_19V = LnbVoltage.VOLTAGE_19V;
 
     /** @hide */
     @IntDef(prefix = "TONE_",
@@ -91,11 +94,11 @@
     /**
      * LNB tone mode not set.
      */
-    public static final int TONE_NONE = Constants.LnbTone.NONE;
+    public static final int TONE_NONE = LnbTone.NONE;
     /**
      * LNB continuous tone mode.
      */
-    public static final int TONE_CONTINUOUS = Constants.LnbTone.CONTINUOUS;
+    public static final int TONE_CONTINUOUS = LnbTone.CONTINUOUS;
 
     /** @hide */
     @IntDef(prefix = "POSITION_",
@@ -106,15 +109,15 @@
     /**
      * LNB position is not defined.
      */
-    public static final int POSITION_UNDEFINED = Constants.LnbPosition.UNDEFINED;
+    public static final int POSITION_UNDEFINED = LnbPosition.UNDEFINED;
     /**
      * Position A of two-band LNBs
      */
-    public static final int POSITION_A = Constants.LnbPosition.POSITION_A;
+    public static final int POSITION_A = LnbPosition.POSITION_A;
     /**
      * Position B of two-band LNBs
      */
-    public static final int POSITION_B = Constants.LnbPosition.POSITION_B;
+    public static final int POSITION_B = LnbPosition.POSITION_B;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -126,22 +129,19 @@
     /**
      * Outgoing Diseqc message overflow.
      */
-    public static final int EVENT_TYPE_DISEQC_RX_OVERFLOW =
-            Constants.LnbEventType.DISEQC_RX_OVERFLOW;
+    public static final int EVENT_TYPE_DISEQC_RX_OVERFLOW = LnbEventType.DISEQC_RX_OVERFLOW;
     /**
      * Outgoing Diseqc message isn't delivered on time.
      */
-    public static final int EVENT_TYPE_DISEQC_RX_TIMEOUT =
-            Constants.LnbEventType.DISEQC_RX_TIMEOUT;
+    public static final int EVENT_TYPE_DISEQC_RX_TIMEOUT = LnbEventType.DISEQC_RX_TIMEOUT;
     /**
      * Incoming Diseqc message has parity error.
      */
-    public static final int EVENT_TYPE_DISEQC_RX_PARITY_ERROR =
-            Constants.LnbEventType.DISEQC_RX_PARITY_ERROR;
+    public static final int EVENT_TYPE_DISEQC_RX_PARITY_ERROR = LnbEventType.DISEQC_RX_PARITY_ERROR;
     /**
      * LNB is overload.
      */
-    public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD;
+    public static final int EVENT_TYPE_LNB_OVERLOAD = LnbEventType.LNB_OVERLOAD;
 
     private static final String TAG = "Lnb";
 
@@ -175,7 +175,13 @@
     private void onEvent(int eventType) {
         synchronized (mCallbackLock) {
             if (mExecutor != null && mCallback != null) {
-                mExecutor.execute(() -> mCallback.onEvent(eventType));
+                mExecutor.execute(() -> {
+                    synchronized (mCallbackLock) {
+                        if (mCallback != null) {
+                            mCallback.onEvent(eventType);
+                        }
+                    }
+                });
             }
         }
     }
@@ -183,7 +189,13 @@
     private void onDiseqcMessage(byte[] diseqcMessage) {
         synchronized (mCallbackLock) {
             if (mExecutor != null && mCallback != null) {
-                mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+                mExecutor.execute(() -> {
+                    synchronized (mCallbackLock) {
+                        if (mCallback != null) {
+                            mCallback.onDiseqcMessage(diseqcMessage);
+                        }
+                    }
+                });
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 3254366..ed5e6ee 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -25,7 +25,9 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.Constant;
+import android.hardware.tv.tuner.Constant64Bit;
+import android.hardware.tv.tuner.FrontendScanType;
 import android.media.tv.TvInputService;
 import android.media.tv.tuner.dvr.DvrPlayback;
 import android.media.tv.tuner.dvr.DvrRecorder;
@@ -85,19 +87,19 @@
     /**
      * Invalid TS packet ID.
      */
-    public static final int INVALID_TS_PID = Constants.Constant.INVALID_TS_PID;
+    public static final int INVALID_TS_PID = Constant.INVALID_TS_PID;
     /**
      * Invalid stream ID.
      */
-    public static final int INVALID_STREAM_ID = Constants.Constant.INVALID_STREAM_ID;
+    public static final int INVALID_STREAM_ID = Constant.INVALID_STREAM_ID;
     /**
      * Invalid filter ID.
      */
-    public static final int INVALID_FILTER_ID = Constants.Constant.INVALID_FILTER_ID;
+    public static final int INVALID_FILTER_ID = Constant.INVALID_FILTER_ID;
     /**
      * Invalid AV Sync ID.
      */
-    public static final int INVALID_AV_SYNC_ID = Constants.Constant.INVALID_AV_SYNC_ID;
+    public static final int INVALID_AV_SYNC_ID = Constant.INVALID_AV_SYNC_ID;
     /**
      * Invalid timestamp.
      *
@@ -113,7 +115,7 @@
      * @see android.media.tv.tuner.filter.MmtpRecordEvent#getPts()
      */
     public static final long INVALID_TIMESTAMP =
-            android.hardware.tv.tuner.V1_1.Constants.Constant64Bit.INVALID_PRESENTATION_TIME_STAMP;
+            Constant64Bit.INVALID_PRESENTATION_TIME_STAMP;
     /**
      * Invalid mpu sequence number in MmtpRecordEvent.
      *
@@ -123,8 +125,7 @@
      * @see android.media.tv.tuner.filter.MmtpRecordEvent#getMpuSequenceNumber()
      */
     public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM =
-            android.hardware.tv.tuner.V1_1.Constants.Constant
-                    .INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
+            Constant.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
     /**
      * Invalid first macroblock address in MmtpRecordEvent and TsRecordEvent.
      *
@@ -135,7 +136,7 @@
      * @see android.media.tv.tuner.filter.TsRecordEvent#getMbInSlice()
      */
     public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FIRST_MACROBLOCK_IN_SLICE;
+            Constant.INVALID_FIRST_MACROBLOCK_IN_SLICE;
     /**
      * Invalid local transport stream id.
      *
@@ -144,30 +145,26 @@
      *
      * @see #linkFrontendToCiCam(int)
      */
-    public static final int INVALID_LTS_ID =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LTS_ID;
+    public static final int INVALID_LTS_ID = Constant.INVALID_LTS_ID;
     /**
      * Invalid 64-bit filter ID.
      */
-    public static final long INVALID_FILTER_ID_LONG =
-            android.hardware.tv.tuner.V1_1.Constants.Constant64Bit.INVALID_FILTER_ID_64BIT;
+    public static final long INVALID_FILTER_ID_LONG = Constant64Bit.INVALID_FILTER_ID_64BIT;
     /**
      * Invalid frequency that is used as the default frontend frequency setting.
      */
     public static final int INVALID_FRONTEND_SETTING_FREQUENCY =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
+            Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
     /**
      * Invalid frontend id.
      */
-    public static final int INVALID_FRONTEND_ID =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_ID;
+    public static final int INVALID_FRONTEND_ID = Constant.INVALID_FRONTEND_ID;
     /**
      * Invalid LNB id.
      *
      * @hide
      */
-    public static final int INVALID_LNB_ID =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LNB_ID;
+    public static final int INVALID_LNB_ID = Constant.INVALID_LNB_ID;
     /**
      * A void key token. It is used to remove the current key from descrambler.
      *
@@ -175,8 +172,7 @@
      * to use this constant to remove current key before closing MediaCas session.
      */
     @NonNull
-    public static final byte[] VOID_KEYTOKEN =
-            {android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_KEYTOKEN};
+    public static final byte[] VOID_KEYTOKEN = {Constant.INVALID_KEYTOKEN};
 
     /** @hide */
     @IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND})
@@ -185,20 +181,20 @@
     /**
      * Scan type undefined.
      */
-    public static final int SCAN_TYPE_UNDEFINED = Constants.FrontendScanType.SCAN_UNDEFINED;
+    public static final int SCAN_TYPE_UNDEFINED = FrontendScanType.SCAN_UNDEFINED;
     /**
      * Scan type auto.
      *
      * <p> Tuner will send {@link android.media.tv.tuner.frontend.ScanCallback#onLocked}
      */
-    public static final int SCAN_TYPE_AUTO = Constants.FrontendScanType.SCAN_AUTO;
+    public static final int SCAN_TYPE_AUTO = FrontendScanType.SCAN_AUTO;
     /**
      * Blind scan.
      *
      * <p>Frequency range is not specified. The {@link android.media.tv.tuner.Tuner} will scan an
      * implementation specific range.
      */
-    public static final int SCAN_TYPE_BLIND = Constants.FrontendScanType.SCAN_BLIND;
+    public static final int SCAN_TYPE_BLIND = FrontendScanType.SCAN_BLIND;
 
 
     /** @hide */
@@ -210,31 +206,33 @@
     /**
      * Operation succeeded.
      */
-    public static final int RESULT_SUCCESS = Constants.Result.SUCCESS;
+    public static final int RESULT_SUCCESS = android.hardware.tv.tuner.Result.SUCCESS;
     /**
      * Operation failed because the corresponding resources are not available.
      */
-    public static final int RESULT_UNAVAILABLE = Constants.Result.UNAVAILABLE;
+    public static final int RESULT_UNAVAILABLE = android.hardware.tv.tuner.Result.UNAVAILABLE;
     /**
      * Operation failed because the corresponding resources are not initialized.
      */
-    public static final int RESULT_NOT_INITIALIZED = Constants.Result.NOT_INITIALIZED;
+    public static final int RESULT_NOT_INITIALIZED =
+            android.hardware.tv.tuner.Result.NOT_INITIALIZED;
     /**
      * Operation failed because it's not in a valid state.
      */
-    public static final int RESULT_INVALID_STATE = Constants.Result.INVALID_STATE;
+    public static final int RESULT_INVALID_STATE = android.hardware.tv.tuner.Result.INVALID_STATE;
     /**
      * Operation failed because there are invalid arguments.
      */
-    public static final int RESULT_INVALID_ARGUMENT = Constants.Result.INVALID_ARGUMENT;
+    public static final int RESULT_INVALID_ARGUMENT =
+            android.hardware.tv.tuner.Result.INVALID_ARGUMENT;
     /**
      * Memory allocation failed.
      */
-    public static final int RESULT_OUT_OF_MEMORY = Constants.Result.OUT_OF_MEMORY;
+    public static final int RESULT_OUT_OF_MEMORY = android.hardware.tv.tuner.Result.OUT_OF_MEMORY;
     /**
      * Operation failed due to unknown errors.
      */
-    public static final int RESULT_UNKNOWN_ERROR = Constants.Result.UNKNOWN_ERROR;
+    public static final int RESULT_UNKNOWN_ERROR = android.hardware.tv.tuner.Result.UNKNOWN_ERROR;
 
 
 
@@ -257,12 +255,12 @@
      * DVR for recording.
      * @hide
      */
-    public static final int DVR_TYPE_RECORD = Constants.DvrType.RECORD;
+    public static final int DVR_TYPE_RECORD = android.hardware.tv.tuner.DvrType.RECORD;
     /**
      * DVR for playback of recorded programs.
      * @hide
      */
-    public static final int DVR_TYPE_PLAYBACK = Constants.DvrType.PLAYBACK;
+    public static final int DVR_TYPE_PLAYBACK = android.hardware.tv.tuner.DvrType.PLAYBACK;
 
     static {
         try {
@@ -432,6 +430,7 @@
             mFrontend = tuner.mFrontend;
             mIsSharedFrontend = true;
         }
+        nativeShareFrontend(mFrontend.mId);
     }
 
     /**
@@ -551,6 +550,7 @@
      * Native method to open frontend of the given ID.
      */
     private native Frontend nativeOpenFrontendByHandle(int handle);
+    private native int nativeShareFrontend(int id);
     @Result
     private native int nativeTune(int type, FrontendSettings settings);
     private native int nativeStopTune();
@@ -629,8 +629,13 @@
                     synchronized (mOnResourceLostListenerLock) {
                         if (mOnResourceLostListener != null
                                 && mOnResourceLostListenerExecutor != null) {
-                            mOnResourceLostListenerExecutor.execute(
-                                    () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+                            mOnResourceLostListenerExecutor.execute(() -> {
+                                synchronized (mOnResourceLostListenerLock) {
+                                    if (mOnResourceLostListener != null) {
+                                        mOnResourceLostListener.onResourceLost(Tuner.this);
+                                    }
+                                }
+                            });
                         }
                     }
                     break;
@@ -1068,7 +1073,13 @@
         Log.d(TAG, "Got event from tuning. Event type: " + eventType);
         synchronized (mOnTuneEventLock) {
             if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) {
-                mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+                mOnTuneEventExecutor.execute(() -> {
+                    synchronized (mOnTuneEventLock) {
+                        if (mOnTuneEventListener != null) {
+                            mOnTuneEventListener.onTuneEvent(eventType);
+                        }
+                    }
+                });
             }
         }
 
@@ -1096,7 +1107,13 @@
 
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onLocked();
+                        }
+                    }
+                });
             }
         }
     }
@@ -1104,7 +1121,13 @@
     private void onScanStopped() {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onScanStopped();
+                        }
+                    }
+                });
             }
         }
     }
@@ -1112,7 +1135,13 @@
     private void onProgress(int percent) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onProgress(percent);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1120,7 +1149,13 @@
     private void onFrequenciesReport(int[] frequency) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onFrequenciesReported(frequency);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1128,7 +1163,13 @@
     private void onSymbolRates(int[] rate) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onSymbolRatesReported(rate);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1136,7 +1177,13 @@
     private void onHierarchy(int hierarchy) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onHierarchyReported(hierarchy);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1144,7 +1191,13 @@
     private void onSignalType(int signalType) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onSignalTypeReported(signalType);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1152,7 +1205,13 @@
     private void onPlpIds(int[] plpIds) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onPlpIdsReported(plpIds);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1160,7 +1219,13 @@
     private void onGroupIds(int[] groupIds) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onGroupIdsReported(groupIds);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1168,8 +1233,13 @@
     private void onInputStreamIds(int[] inputStreamIds) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onInputStreamIdsReported(inputStreamIds);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1177,8 +1247,13 @@
     private void onDvbsStandard(int dvbsStandandard) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onDvbsStandardReported(dvbsStandandard);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1186,8 +1261,13 @@
     private void onDvbtStandard(int dvbtStandard) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onDvbtStandardReported(dvbtStandard);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1195,7 +1275,13 @@
     private void onAnalogSifStandard(int sif) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onAnalogSifStandardReported(sif);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1203,8 +1289,13 @@
     private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1212,8 +1303,13 @@
     private void onModulationReported(int modulation) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onModulationReported(modulation));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onModulationReported(modulation);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1221,8 +1317,13 @@
     private void onPriorityReported(boolean isHighPriority) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onPriorityReported(isHighPriority));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onPriorityReported(isHighPriority);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1230,8 +1331,13 @@
     private void onDvbcAnnexReported(int dvbcAnnex) {
         synchronized (mScanCallbackLock) {
             if (mScanCallbackExecutor != null && mScanCallback != null) {
-                mScanCallbackExecutor.execute(
-                        () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+                mScanCallbackExecutor.execute(() -> {
+                    synchronized (mScanCallbackLock) {
+                        if (mScanCallback != null) {
+                            mScanCallback.onDvbcAnnexReported(dvbcAnnex);
+                        }
+                    }
+                });
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index a13077c..3a15daf 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -17,7 +17,11 @@
 package android.media.tv.tuner;
 
 import android.annotation.Nullable;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.DemuxAlpFilterType;
+import android.hardware.tv.tuner.DemuxIpFilterType;
+import android.hardware.tv.tuner.DemuxMmtpFilterType;
+import android.hardware.tv.tuner.DemuxTlvFilterType;
+import android.hardware.tv.tuner.DemuxTsFilterType;
 import android.media.tv.tuner.filter.Filter;
 
 /**
@@ -37,44 +41,44 @@
         if (mainType == Filter.TYPE_TS) {
             switch (subtype) {
                 case Filter.SUBTYPE_UNDEFINED:
-                    return Constants.DemuxTsFilterType.UNDEFINED;
+                    return DemuxTsFilterType.UNDEFINED;
                 case Filter.SUBTYPE_SECTION:
-                    return Constants.DemuxTsFilterType.SECTION;
+                    return DemuxTsFilterType.SECTION;
                 case Filter.SUBTYPE_PES:
-                    return Constants.DemuxTsFilterType.PES;
+                    return DemuxTsFilterType.PES;
                 case Filter.SUBTYPE_TS:
-                    return Constants.DemuxTsFilterType.TS;
+                    return DemuxTsFilterType.TS;
                 case Filter.SUBTYPE_AUDIO:
-                    return Constants.DemuxTsFilterType.AUDIO;
+                    return DemuxTsFilterType.AUDIO;
                 case Filter.SUBTYPE_VIDEO:
-                    return Constants.DemuxTsFilterType.VIDEO;
+                    return DemuxTsFilterType.VIDEO;
                 case Filter.SUBTYPE_PCR:
-                    return Constants.DemuxTsFilterType.PCR;
+                    return DemuxTsFilterType.PCR;
                 case Filter.SUBTYPE_RECORD:
-                    return Constants.DemuxTsFilterType.RECORD;
+                    return DemuxTsFilterType.RECORD;
                 case Filter.SUBTYPE_TEMI:
-                    return Constants.DemuxTsFilterType.TEMI;
+                    return DemuxTsFilterType.TEMI;
                 default:
                     break;
             }
         } else if (mainType == Filter.TYPE_MMTP) {
             switch (subtype) {
                 case Filter.SUBTYPE_UNDEFINED:
-                    return Constants.DemuxMmtpFilterType.UNDEFINED;
+                    return DemuxMmtpFilterType.UNDEFINED;
                 case Filter.SUBTYPE_SECTION:
-                    return Constants.DemuxMmtpFilterType.SECTION;
+                    return DemuxMmtpFilterType.SECTION;
                 case Filter.SUBTYPE_PES:
-                    return Constants.DemuxMmtpFilterType.PES;
+                    return DemuxMmtpFilterType.PES;
                 case Filter.SUBTYPE_MMTP:
-                    return Constants.DemuxMmtpFilterType.MMTP;
+                    return DemuxMmtpFilterType.MMTP;
                 case Filter.SUBTYPE_AUDIO:
-                    return Constants.DemuxMmtpFilterType.AUDIO;
+                    return DemuxMmtpFilterType.AUDIO;
                 case Filter.SUBTYPE_VIDEO:
-                    return Constants.DemuxMmtpFilterType.VIDEO;
+                    return DemuxMmtpFilterType.VIDEO;
                 case Filter.SUBTYPE_RECORD:
-                    return Constants.DemuxMmtpFilterType.RECORD;
+                    return DemuxMmtpFilterType.RECORD;
                 case Filter.SUBTYPE_DOWNLOAD:
-                    return Constants.DemuxMmtpFilterType.DOWNLOAD;
+                    return DemuxMmtpFilterType.DOWNLOAD;
                 default:
                     break;
             }
@@ -82,43 +86,43 @@
         } else if (mainType == Filter.TYPE_IP) {
             switch (subtype) {
                 case Filter.SUBTYPE_UNDEFINED:
-                    return Constants.DemuxIpFilterType.UNDEFINED;
+                    return DemuxIpFilterType.UNDEFINED;
                 case Filter.SUBTYPE_SECTION:
-                    return Constants.DemuxIpFilterType.SECTION;
+                    return DemuxIpFilterType.SECTION;
                 case Filter.SUBTYPE_NTP:
-                    return Constants.DemuxIpFilterType.NTP;
+                    return DemuxIpFilterType.NTP;
                 case Filter.SUBTYPE_IP_PAYLOAD:
-                    return Constants.DemuxIpFilterType.IP_PAYLOAD;
+                    return DemuxIpFilterType.IP_PAYLOAD;
                 case Filter.SUBTYPE_IP:
-                    return Constants.DemuxIpFilterType.IP;
+                    return DemuxIpFilterType.IP;
                 case Filter.SUBTYPE_PAYLOAD_THROUGH:
-                    return Constants.DemuxIpFilterType.PAYLOAD_THROUGH;
+                    return DemuxIpFilterType.PAYLOAD_THROUGH;
                 default:
                     break;
             }
         } else if (mainType == Filter.TYPE_TLV) {
             switch (subtype) {
                 case Filter.SUBTYPE_UNDEFINED:
-                    return Constants.DemuxTlvFilterType.UNDEFINED;
+                    return DemuxTlvFilterType.UNDEFINED;
                 case Filter.SUBTYPE_SECTION:
-                    return Constants.DemuxTlvFilterType.SECTION;
+                    return DemuxTlvFilterType.SECTION;
                 case Filter.SUBTYPE_TLV:
-                    return Constants.DemuxTlvFilterType.TLV;
+                    return DemuxTlvFilterType.TLV;
                 case Filter.SUBTYPE_PAYLOAD_THROUGH:
-                    return Constants.DemuxTlvFilterType.PAYLOAD_THROUGH;
+                    return DemuxTlvFilterType.PAYLOAD_THROUGH;
                 default:
                     break;
             }
         } else if (mainType == Filter.TYPE_ALP) {
             switch (subtype) {
                 case Filter.SUBTYPE_UNDEFINED:
-                    return Constants.DemuxAlpFilterType.UNDEFINED;
+                    return DemuxAlpFilterType.UNDEFINED;
                 case Filter.SUBTYPE_SECTION:
-                    return Constants.DemuxAlpFilterType.SECTION;
+                    return DemuxAlpFilterType.SECTION;
                 case Filter.SUBTYPE_PTP:
-                    return Constants.DemuxAlpFilterType.PTP;
+                    return DemuxAlpFilterType.PTP;
                 case Filter.SUBTYPE_PAYLOAD_THROUGH:
-                    return Constants.DemuxAlpFilterType.PAYLOAD_THROUGH;
+                    return DemuxAlpFilterType.PAYLOAD_THROUGH;
                 default:
                     break;
             }
diff --git a/media/java/android/media/tv/tuner/TunerVersionChecker.java b/media/java/android/media/tv/tuner/TunerVersionChecker.java
index b40ba1e..3e13bed 100644
--- a/media/java/android/media/tv/tuner/TunerVersionChecker.java
+++ b/media/java/android/media/tv/tuner/TunerVersionChecker.java
@@ -38,8 +38,9 @@
     private TunerVersionChecker() {}
 
     /** @hide */
-    @IntDef(prefix = "TUNER_VERSION_", value = {TUNER_VERSION_UNKNOWN, TUNER_VERSION_1_0,
-                                                TUNER_VERSION_1_1})
+    @IntDef(prefix = "TUNER_VERSION_",
+            value = {TUNER_VERSION_UNKNOWN, TUNER_VERSION_1_0, TUNER_VERSION_1_1,
+                    TUNER_VERSION_2_0})
     @Retention(RetentionPolicy.SOURCE)
     public @interface TunerVersion {}
     /**
@@ -54,6 +55,10 @@
      * Tuner version 1.1.
      */
     public static final int TUNER_VERSION_1_1 = ((1 << 16) | 1);
+    /**
+     * Tuner version 2.0.
+     */
+    public static final int TUNER_VERSION_2_0 = (2 << 16);
 
     /**
      * Get the current running Tuner version.
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 1f805d7..cfd8583 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -20,7 +20,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.Tuner.Result;
 import android.media.tv.tuner.TunerUtils;
@@ -56,25 +55,27 @@
     /**
      * The space of the playback is empty.
      */
-    public static final int PLAYBACK_STATUS_EMPTY = Constants.PlaybackStatus.SPACE_EMPTY;
+    public static final int PLAYBACK_STATUS_EMPTY =
+            android.hardware.tv.tuner.PlaybackStatus.SPACE_EMPTY;
     /**
      * The space of the playback is almost empty.
      *
      * <p> the threshold is set in {@link DvrSettings}.
      */
     public static final int PLAYBACK_STATUS_ALMOST_EMPTY =
-            Constants.PlaybackStatus.SPACE_ALMOST_EMPTY;
+            android.hardware.tv.tuner.PlaybackStatus.SPACE_ALMOST_EMPTY;
     /**
      * The space of the playback is almost full.
      *
      * <p> the threshold is set in {@link DvrSettings}.
      */
     public static final int PLAYBACK_STATUS_ALMOST_FULL =
-            Constants.PlaybackStatus.SPACE_ALMOST_FULL;
+            android.hardware.tv.tuner.PlaybackStatus.SPACE_ALMOST_FULL;
     /**
      * The space of the playback is full.
      */
-    public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
+    public static final int PLAYBACK_STATUS_FULL =
+            android.hardware.tv.tuner.PlaybackStatus.SPACE_FULL;
 
     private static final String TAG = "TvTunerPlayback";
 
@@ -119,7 +120,13 @@
         }
         synchronized (mListenerLock) {
             if (mExecutor != null && mListener != null) {
-                mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+                mExecutor.execute(() -> {
+                    synchronized (mListenerLock) {
+                        if (mListener != null) {
+                            mListener.onPlaybackStatusChanged(status);
+                        }
+                    }
+                });
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 2b69466..212a713 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -82,7 +82,13 @@
         }
         synchronized (mListenerLock) {
             if (mExecutor != null && mListener != null) {
-                mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+                mExecutor.execute(() -> {
+                    synchronized (mListenerLock) {
+                        if (mListener != null) {
+                            mListener.onRecordStatusChanged(status);
+                        }
+                    }
+                });
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/dvr/DvrSettings.java b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
index 60f0d16..0c4af4b 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrSettings.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
@@ -20,7 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.DataFormat;
 import android.media.tv.tuner.filter.Filter;
 
 import java.lang.annotation.Retention;
@@ -43,19 +43,19 @@
     /**
      * Transport Stream.
      */
-    public static final int DATA_FORMAT_TS = Constants.DataFormat.TS;
+    public static final int DATA_FORMAT_TS = android.hardware.tv.tuner.DataFormat.TS;
     /**
      * Packetized Elementary Stream.
      */
-    public static final int DATA_FORMAT_PES = Constants.DataFormat.PES;
+    public static final int DATA_FORMAT_PES = android.hardware.tv.tuner.DataFormat.PES;
     /**
      * Elementary Stream.
      */
-    public static final int DATA_FORMAT_ES = Constants.DataFormat.ES;
+    public static final int DATA_FORMAT_ES = android.hardware.tv.tuner.DataFormat.ES;
     /**
      * TLV (type-length-value) Stream for SHV
      */
-    public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV;
+    public static final int DATA_FORMAT_SHV_TLV = android.hardware.tv.tuner.DataFormat.SHV_TLV;
 
 
     @Filter.Status
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 29bc2c9..bac3b56 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.DemuxAlpLengthType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -63,17 +63,17 @@
     /**
      * Length type not defined.
      */
-    public static final int LENGTH_TYPE_UNDEFINED = Constants.DemuxAlpLengthType.UNDEFINED;
+    public static final int LENGTH_TYPE_UNDEFINED = DemuxAlpLengthType.UNDEFINED;
     /**
      * Length does NOT include additional header.
      */
     public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER =
-            Constants.DemuxAlpLengthType.WITHOUT_ADDITIONAL_HEADER;
+            DemuxAlpLengthType.WITHOUT_ADDITIONAL_HEADER;
     /**
      * Length includes additional header.
      */
     public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER =
-            Constants.DemuxAlpLengthType.WITH_ADDITIONAL_HEADER;
+            DemuxAlpLengthType.WITH_ADDITIONAL_HEADER;
 
 
     private final int mPacketType;
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index 25457a7..8bcf3d2 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_1.Constants;
 import android.media.tv.tuner.TunerUtils;
 import android.media.tv.tuner.TunerVersionChecker;
 
@@ -46,55 +45,60 @@
     /*
      * Undefined Video stream type
      */
-    public static final int VIDEO_STREAM_TYPE_UNDEFINED = Constants.VideoStreamType.UNDEFINED;
+    public static final int VIDEO_STREAM_TYPE_UNDEFINED =
+            android.hardware.tv.tuner.VideoStreamType.UNDEFINED;
     /*
      * ITU-T | ISO/IEC Reserved
      */
-    public static final int VIDEO_STREAM_TYPE_RESERVED = Constants.VideoStreamType.RESERVED;
+    public static final int VIDEO_STREAM_TYPE_RESERVED =
+            android.hardware.tv.tuner.VideoStreamType.RESERVED;
     /*
      * ISO/IEC 11172
      */
-    public static final int VIDEO_STREAM_TYPE_MPEG1 = Constants.VideoStreamType.MPEG1;
+    public static final int VIDEO_STREAM_TYPE_MPEG1 =
+            android.hardware.tv.tuner.VideoStreamType.MPEG1;
     /*
      * ITU-T Rec.H.262 and ISO/IEC 13818-2
      */
-    public static final int VIDEO_STREAM_TYPE_MPEG2 = Constants.VideoStreamType.MPEG2;
+    public static final int VIDEO_STREAM_TYPE_MPEG2 =
+            android.hardware.tv.tuner.VideoStreamType.MPEG2;
     /*
      * ISO/IEC 14496-2 (MPEG-4 H.263 based video)
      */
-    public static final int VIDEO_STREAM_TYPE_MPEG4P2 = Constants.VideoStreamType.MPEG4P2;
+    public static final int VIDEO_STREAM_TYPE_MPEG4P2 =
+            android.hardware.tv.tuner.VideoStreamType.MPEG4P2;
     /*
      * ITU-T Rec.H.264 and ISO/IEC 14496-10
      */
-    public static final int VIDEO_STREAM_TYPE_AVC = Constants.VideoStreamType.AVC;
+    public static final int VIDEO_STREAM_TYPE_AVC = android.hardware.tv.tuner.VideoStreamType.AVC;
     /*
      * ITU-T Rec. H.265 and ISO/IEC 23008-2
      */
-    public static final int VIDEO_STREAM_TYPE_HEVC = Constants.VideoStreamType.HEVC;
+    public static final int VIDEO_STREAM_TYPE_HEVC = android.hardware.tv.tuner.VideoStreamType.HEVC;
     /*
      * Microsoft VC.1
      */
-    public static final int VIDEO_STREAM_TYPE_VC1 = Constants.VideoStreamType.VC1;
+    public static final int VIDEO_STREAM_TYPE_VC1 = android.hardware.tv.tuner.VideoStreamType.VC1;
     /*
      * Google VP8
      */
-    public static final int VIDEO_STREAM_TYPE_VP8 = Constants.VideoStreamType.VP8;
+    public static final int VIDEO_STREAM_TYPE_VP8 = android.hardware.tv.tuner.VideoStreamType.VP8;
     /*
      * Google VP9
      */
-    public static final int VIDEO_STREAM_TYPE_VP9 = Constants.VideoStreamType.VP9;
+    public static final int VIDEO_STREAM_TYPE_VP9 = android.hardware.tv.tuner.VideoStreamType.VP9;
     /*
      * AOMedia Video 1
      */
-    public static final int VIDEO_STREAM_TYPE_AV1 = Constants.VideoStreamType.AV1;
+    public static final int VIDEO_STREAM_TYPE_AV1 = android.hardware.tv.tuner.VideoStreamType.AV1;
     /*
      * Chinese Standard
      */
-    public static final int VIDEO_STREAM_TYPE_AVS = Constants.VideoStreamType.AVS;
+    public static final int VIDEO_STREAM_TYPE_AVS = android.hardware.tv.tuner.VideoStreamType.AVS;
     /*
      * New Chinese Standard
      */
-    public static final int VIDEO_STREAM_TYPE_AVS2 = Constants.VideoStreamType.AVS2;
+    public static final int VIDEO_STREAM_TYPE_AVS2 = android.hardware.tv.tuner.VideoStreamType.AVS2;
 
     /** @hide */
     @IntDef(prefix = "AUDIO_STREAM_TYPE_",
@@ -110,67 +114,73 @@
     /*
      * Undefined Audio stream type
      */
-    public static final int AUDIO_STREAM_TYPE_UNDEFINED = Constants.AudioStreamType.UNDEFINED;
+    public static final int AUDIO_STREAM_TYPE_UNDEFINED =
+            android.hardware.tv.tuner.AudioStreamType.UNDEFINED;
     /*
      * Uncompressed Audio
      */
-    public static final int AUDIO_STREAM_TYPE_PCM = Constants.AudioStreamType.PCM;
+    public static final int AUDIO_STREAM_TYPE_PCM = android.hardware.tv.tuner.AudioStreamType.PCM;
     /*
      * MPEG Audio Layer III versions
      */
-    public static final int AUDIO_STREAM_TYPE_MP3 = Constants.AudioStreamType.MP3;
+    public static final int AUDIO_STREAM_TYPE_MP3 = android.hardware.tv.tuner.AudioStreamType.MP3;
     /*
      * ISO/IEC 11172 Audio
      */
-    public static final int AUDIO_STREAM_TYPE_MPEG1 = Constants.AudioStreamType.MPEG1;
+    public static final int AUDIO_STREAM_TYPE_MPEG1 =
+            android.hardware.tv.tuner.AudioStreamType.MPEG1;
     /*
      * ISO/IEC 13818-3
      */
-    public static final int AUDIO_STREAM_TYPE_MPEG2 = Constants.AudioStreamType.MPEG2;
+    public static final int AUDIO_STREAM_TYPE_MPEG2 =
+            android.hardware.tv.tuner.AudioStreamType.MPEG2;
     /*
      * ISO/IEC 23008-3 (MPEG-H Part 3)
      */
-    public static final int AUDIO_STREAM_TYPE_MPEGH = Constants.AudioStreamType.MPEGH;
+    public static final int AUDIO_STREAM_TYPE_MPEGH =
+            android.hardware.tv.tuner.AudioStreamType.MPEGH;
     /*
      * ISO/IEC 14496-3
      */
-    public static final int AUDIO_STREAM_TYPE_AAC = Constants.AudioStreamType.AAC;
+    public static final int AUDIO_STREAM_TYPE_AAC = android.hardware.tv.tuner.AudioStreamType.AAC;
     /*
      * Dolby Digital
      */
-    public static final int AUDIO_STREAM_TYPE_AC3 = Constants.AudioStreamType.AC3;
+    public static final int AUDIO_STREAM_TYPE_AC3 = android.hardware.tv.tuner.AudioStreamType.AC3;
     /*
      * Dolby Digital Plus
      */
-    public static final int AUDIO_STREAM_TYPE_EAC3 = Constants.AudioStreamType.EAC3;
+    public static final int AUDIO_STREAM_TYPE_EAC3 = android.hardware.tv.tuner.AudioStreamType.EAC3;
     /*
      * Dolby AC-4
      */
-    public static final int AUDIO_STREAM_TYPE_AC4 = Constants.AudioStreamType.AC4;
+    public static final int AUDIO_STREAM_TYPE_AC4 = android.hardware.tv.tuner.AudioStreamType.AC4;
     /*
      * Basic DTS
      */
-    public static final int AUDIO_STREAM_TYPE_DTS = Constants.AudioStreamType.DTS;
+    public static final int AUDIO_STREAM_TYPE_DTS = android.hardware.tv.tuner.AudioStreamType.DTS;
     /*
      * High Resolution DTS
      */
-    public static final int AUDIO_STREAM_TYPE_DTS_HD = Constants.AudioStreamType.DTS_HD;
+    public static final int AUDIO_STREAM_TYPE_DTS_HD =
+            android.hardware.tv.tuner.AudioStreamType.DTS_HD;
     /*
      * Windows Media Audio
      */
-    public static final int AUDIO_STREAM_TYPE_WMA = Constants.AudioStreamType.WMA;
+    public static final int AUDIO_STREAM_TYPE_WMA = android.hardware.tv.tuner.AudioStreamType.WMA;
     /*
      * Opus Interactive Audio Codec
      */
-    public static final int AUDIO_STREAM_TYPE_OPUS = Constants.AudioStreamType.OPUS;
+    public static final int AUDIO_STREAM_TYPE_OPUS = android.hardware.tv.tuner.AudioStreamType.OPUS;
     /*
      * VORBIS Interactive Audio Codec
      */
-    public static final int AUDIO_STREAM_TYPE_VORBIS = Constants.AudioStreamType.VORBIS;
+    public static final int AUDIO_STREAM_TYPE_VORBIS =
+            android.hardware.tv.tuner.AudioStreamType.VORBIS;
     /*
      * SJ/T 11368-2006
      */
-    public static final int AUDIO_STREAM_TYPE_DRA = Constants.AudioStreamType.DRA;
+    public static final int AUDIO_STREAM_TYPE_DRA = android.hardware.tv.tuner.AudioStreamType.DRA;
 
 
     private final boolean mIsPassthrough;
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 33742ff..e7612bc 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -21,7 +21,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.DemuxFilterMainType;
+import android.hardware.tv.tuner.DemuxFilterMonitorEventType;
+import android.hardware.tv.tuner.DemuxFilterStatus;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.Tuner.Result;
 import android.media.tv.tuner.TunerUtils;
@@ -53,23 +55,23 @@
     /**
      * TS filter type.
      */
-    public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
+    public static final int TYPE_TS = DemuxFilterMainType.TS;
     /**
      * MMTP filter type.
      */
-    public static final int TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
+    public static final int TYPE_MMTP = DemuxFilterMainType.MMTP;
     /**
      * IP filter type.
      */
-    public static final int TYPE_IP = Constants.DemuxFilterMainType.IP;
+    public static final int TYPE_IP = DemuxFilterMainType.IP;
     /**
      * TLV filter type.
      */
-    public static final int TYPE_TLV = Constants.DemuxFilterMainType.TLV;
+    public static final int TYPE_TLV = DemuxFilterMainType.TLV;
     /**
      * ALP filter type.
      */
-    public static final int TYPE_ALP = Constants.DemuxFilterMainType.ALP;
+    public static final int TYPE_ALP = DemuxFilterMainType.ALP;
 
     /** @hide */
     @IntDef(prefix = "SUBTYPE_",
@@ -158,7 +160,7 @@
     /**
      * The status of a filter that the data in the filter buffer is ready to be read.
      */
-    public static final int STATUS_DATA_READY = Constants.DemuxFilterStatus.DATA_READY;
+    public static final int STATUS_DATA_READY = DemuxFilterStatus.DATA_READY;
     /**
      * The status of a filter that the amount of available data in the filter buffer is at low
      * level.
@@ -166,19 +168,19 @@
      * The value is set to 25 percent of the buffer size by default. It can be changed when
      * configuring the filter.
      */
-    public static final int STATUS_LOW_WATER = Constants.DemuxFilterStatus.LOW_WATER;
+    public static final int STATUS_LOW_WATER = DemuxFilterStatus.LOW_WATER;
     /**
      * The status of a filter that the amount of available data in the filter buffer is at high
      * level.
      * The value is set to 75 percent of the buffer size by default. It can be changed when
      * configuring the filter.
      */
-    public static final int STATUS_HIGH_WATER = Constants.DemuxFilterStatus.HIGH_WATER;
+    public static final int STATUS_HIGH_WATER = DemuxFilterStatus.HIGH_WATER;
     /**
      * The status of a filter that the filter buffer is full and newly filtered data is being
      * discarded.
      */
-    public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
+    public static final int STATUS_OVERFLOW = DemuxFilterStatus.OVERFLOW;
 
     /** @hide */
     @IntDef(flag = true,
@@ -192,17 +194,17 @@
      * Content’s scrambling status is unknown
      */
     public static final int SCRAMBLING_STATUS_UNKNOWN =
-            android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.UNKNOWN;
+            android.hardware.tv.tuner.ScramblingStatus.UNKNOWN;
     /**
      * Content is not scrambled.
      */
     public static final int SCRAMBLING_STATUS_NOT_SCRAMBLED =
-            android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.NOT_SCRAMBLED;
+            android.hardware.tv.tuner.ScramblingStatus.NOT_SCRAMBLED;
     /**
      * Content is scrambled.
      */
     public static final int SCRAMBLING_STATUS_SCRAMBLED =
-            android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.SCRAMBLED;
+            android.hardware.tv.tuner.ScramblingStatus.SCRAMBLED;
 
     /** @hide */
     @IntDef(flag = true,
@@ -215,12 +217,11 @@
      * Monitor scrambling status change.
      */
     public static final int MONITOR_EVENT_SCRAMBLING_STATUS =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxFilterMonitorEventType.SCRAMBLING_STATUS;
+            DemuxFilterMonitorEventType.SCRAMBLING_STATUS;
     /**
      * Monitor ip cid change.
      */
-    public static final int MONITOR_EVENT_IP_CID_CHANGE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxFilterMonitorEventType.IP_CID_CHANGE;
+    public static final int MONITOR_EVENT_IP_CID_CHANGE = DemuxFilterMonitorEventType.IP_CID_CHANGE;
 
     private static final String TAG = "Filter";
 
@@ -256,7 +257,13 @@
     private void onFilterStatus(int status) {
         synchronized (mCallbackLock) {
             if (mCallback != null && mExecutor != null) {
-                mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+                mExecutor.execute(() -> {
+                    synchronized (mCallbackLock) {
+                        if (mCallback != null) {
+                            mCallback.onFilterStatusChanged(this, status);
+                        }
+                    }
+                });
             }
         }
     }
@@ -264,7 +271,13 @@
     private void onFilterEvent(FilterEvent[] events) {
         synchronized (mCallbackLock) {
             if (mCallback != null && mExecutor != null) {
-                mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+                mExecutor.execute(() -> {
+                    synchronized (mCallbackLock) {
+                        if (mCallback != null) {
+                            mCallback.onFilterEvent(this, events);
+                        }
+                    }
+                });
             }
         }
     }
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index 4b69807..6578464 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.Size;
 import android.annotation.SystemApi;
+import android.hardware.tv.tuner.Constant;
 import android.media.tv.tuner.TunerVersionChecker;
 
 /**
@@ -33,8 +34,7 @@
     /**
      * Undefined filter type.
      */
-    public static final int INVALID_IP_FILTER_CONTEXT_ID =
-            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_IP_FILTER_CONTEXT_ID;
+    public static final int INVALID_IP_FILTER_CONTEXT_ID = Constant.INVALID_IP_FILTER_CONTEXT_ID;
 
     private final byte[] mSrcIpAddress;
     private final byte[] mDstIpAddress;
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index 91992af..cd70365 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -19,7 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.DemuxRecordScIndexType;
+import android.hardware.tv.tuner.DemuxScHevcIndex;
+import android.hardware.tv.tuner.DemuxScIndex;
+import android.hardware.tv.tuner.DemuxTsIndex;
 import android.media.tv.tuner.TunerUtils;
 
 import java.lang.annotation.Retention;
@@ -57,88 +60,80 @@
     /**
      * TS index FIRST_PACKET.
      */
-    public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+    public static final int TS_INDEX_FIRST_PACKET = DemuxTsIndex.FIRST_PACKET;
     /**
      * TS index PAYLOAD_UNIT_START_INDICATOR.
      */
     public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
-            Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+            DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
     /**
      * TS index CHANGE_TO_NOT_SCRAMBLED.
      */
-    public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
+    public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
     /**
      * TS index CHANGE_TO_EVEN_SCRAMBLED.
      */
     public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
+            DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
     /**
      * TS index CHANGE_TO_ODD_SCRAMBLED.
      */
-    public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
-            Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
+    public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
     /**
      * TS index DISCONTINUITY_INDICATOR.
      */
-    public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
-            Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
+    public static final int TS_INDEX_DISCONTINUITY_INDICATOR = DemuxTsIndex.DISCONTINUITY_INDICATOR;
     /**
      * TS index RANDOM_ACCESS_INDICATOR.
      */
-    public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
-            Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
+    public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR = DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
     /**
      * TS index PRIORITY_INDICATOR.
      */
-    public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
+    public static final int TS_INDEX_PRIORITY_INDICATOR = DemuxTsIndex.PRIORITY_INDICATOR;
     /**
      * TS index PCR_FLAG.
      */
-    public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
+    public static final int TS_INDEX_PCR_FLAG = DemuxTsIndex.PCR_FLAG;
     /**
      * TS index OPCR_FLAG.
      */
-    public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
+    public static final int TS_INDEX_OPCR_FLAG = DemuxTsIndex.OPCR_FLAG;
     /**
      * TS index SPLICING_POINT_FLAG.
      */
-    public static final int TS_INDEX_SPLICING_POINT_FLAG =
-            Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
+    public static final int TS_INDEX_SPLICING_POINT_FLAG = DemuxTsIndex.SPLICING_POINT_FLAG;
     /**
      * TS index PRIVATE_DATA.
      */
-    public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
+    public static final int TS_INDEX_PRIVATE_DATA = DemuxTsIndex.PRIVATE_DATA;
     /**
      * TS index ADAPTATION_EXTENSION_FLAG.
      */
     public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
-            Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+            DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
     /**
      * Index the address of MPEG Media Transport Packet Table(MPT).
      */
-    public static final int MPT_INDEX_MPT =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_MPT;
+    public static final int MPT_INDEX_MPT = DemuxTsIndex.MPT_INDEX_MPT;
     /**
      * Index the address of Video.
      */
-    public static final int MPT_INDEX_VIDEO =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_VIDEO;
+    public static final int MPT_INDEX_VIDEO = DemuxTsIndex.MPT_INDEX_VIDEO;
     /**
      * Index the address of Audio.
      */
-    public static final int MPT_INDEX_AUDIO =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_AUDIO;
+    public static final int MPT_INDEX_AUDIO = DemuxTsIndex.MPT_INDEX_AUDIO;
     /**
      * Index to indicate this is a target of timestamp extraction for video.
      */
     public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_VIDEO;
+            DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_VIDEO;
     /**
      * Index to indicate this is a target of timestamp extraction for audio.
      */
     public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_AUDIO;
+            DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_AUDIO;
 
 
     /** @hide */
@@ -150,15 +145,15 @@
     /**
      * Start Code Index is not used.
      */
-    public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE;
+    public static final int INDEX_TYPE_NONE = DemuxRecordScIndexType.NONE;
     /**
      * Start Code index.
      */
-    public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC;
+    public static final int INDEX_TYPE_SC = DemuxRecordScIndexType.SC;
     /**
      * Start Code index for HEVC.
      */
-    public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC;
+    public static final int INDEX_TYPE_SC_HEVC = DemuxRecordScIndexType.SC_HEVC;
 
     /**
      * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
@@ -176,44 +171,39 @@
     /**
      * SC index for a new I-frame.
      */
-    public static final int SC_INDEX_I_FRAME = Constants.DemuxScIndex.I_FRAME;
+    public static final int SC_INDEX_I_FRAME = DemuxScIndex.I_FRAME;
     /**
      * SC index for a new P-frame.
      */
-    public static final int SC_INDEX_P_FRAME = Constants.DemuxScIndex.P_FRAME;
+    public static final int SC_INDEX_P_FRAME = DemuxScIndex.P_FRAME;
     /**
      * SC index for a new B-frame.
      */
-    public static final int SC_INDEX_B_FRAME = Constants.DemuxScIndex.B_FRAME;
+    public static final int SC_INDEX_B_FRAME = DemuxScIndex.B_FRAME;
     /**
      * SC index for a new sequence.
      */
-    public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
+    public static final int SC_INDEX_SEQUENCE = DemuxScIndex.SEQUENCE;
     /**
      * All blocks are coded as I blocks.
      */
-    public static final int SC_INDEX_I_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.I_SLICE;
+    public static final int SC_INDEX_I_SLICE = DemuxScIndex.I_SLICE;
     /**
      * Blocks are coded as I or P blocks.
      */
-    public static final int SC_INDEX_P_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.P_SLICE;
+    public static final int SC_INDEX_P_SLICE = DemuxScIndex.P_SLICE;
     /**
      * Blocks are coded as I, P or B blocks.
      */
-    public static final int SC_INDEX_B_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.B_SLICE;
+    public static final int SC_INDEX_B_SLICE = DemuxScIndex.B_SLICE;
     /**
      * A so-called switching I slice that is coded.
      */
-    public static final int SC_INDEX_SI_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SI_SLICE;
+    public static final int SC_INDEX_SI_SLICE = DemuxScIndex.SI_SLICE;
     /**
      * A so-called switching P slice that is coded.
      */
-    public static final int SC_INDEX_SP_SLICE =
-            android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SP_SLICE;
+    public static final int SC_INDEX_SP_SLICE = DemuxScIndex.SP_SLICE;
 
     /**
      * Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
@@ -231,41 +221,35 @@
     /**
      * SC HEVC index SPS.
      */
-    public static final int SC_HEVC_INDEX_SPS = Constants.DemuxScHevcIndex.SPS;
+    public static final int SC_HEVC_INDEX_SPS = DemuxScHevcIndex.SPS;
     /**
      * SC HEVC index AUD.
      */
-    public static final int SC_HEVC_INDEX_AUD = Constants.DemuxScHevcIndex.AUD;
+    public static final int SC_HEVC_INDEX_AUD = DemuxScHevcIndex.AUD;
     /**
      * SC HEVC index SLICE_CE_BLA_W_LP.
      */
-    public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP =
-            Constants.DemuxScHevcIndex.SLICE_CE_BLA_W_LP;
+    public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP = DemuxScHevcIndex.SLICE_CE_BLA_W_LP;
     /**
      * SC HEVC index SLICE_BLA_W_RADL.
      */
-    public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL =
-            Constants.DemuxScHevcIndex.SLICE_BLA_W_RADL;
+    public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = DemuxScHevcIndex.SLICE_BLA_W_RADL;
     /**
      * SC HEVC index SLICE_BLA_N_LP.
      */
-    public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP =
-            Constants.DemuxScHevcIndex.SLICE_BLA_N_LP;
+    public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = DemuxScHevcIndex.SLICE_BLA_N_LP;
     /**
      * SC HEVC index SLICE_IDR_W_RADL.
      */
-    public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL =
-            Constants.DemuxScHevcIndex.SLICE_IDR_W_RADL;
+    public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL = DemuxScHevcIndex.SLICE_IDR_W_RADL;
     /**
      * SC HEVC index SLICE_IDR_N_LP.
      */
-    public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP =
-            Constants.DemuxScHevcIndex.SLICE_IDR_N_LP;
+    public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP = DemuxScHevcIndex.SLICE_IDR_N_LP;
     /**
      * SC HEVC index SLICE_TRAIL_CRA.
      */
-    public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA =
-            Constants.DemuxScHevcIndex.SLICE_TRAIL_CRA;
+    public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = DemuxScHevcIndex.SLICE_TRAIL_CRA;
 
     /**
      * @hide
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index b2c3fd2..768f1d3 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -20,7 +20,9 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendAnalogAftFlag;
+import android.hardware.tv.tuner.FrontendAnalogSifStandard;
+import android.hardware.tv.tuner.FrontendAnalogType;
 import android.media.tv.tuner.TunerVersionChecker;
 
 import java.lang.annotation.Retention;
@@ -45,39 +47,39 @@
     /**
      * Undefined analog signal type.
      */
-    public static final int SIGNAL_TYPE_UNDEFINED = Constants.FrontendAnalogType.UNDEFINED;
+    public static final int SIGNAL_TYPE_UNDEFINED = FrontendAnalogType.UNDEFINED;
     /**
      * AUTO analog signal type.
      */
-    public static final int SIGNAL_TYPE_AUTO = Constants.FrontendAnalogType.AUTO;
+    public static final int SIGNAL_TYPE_AUTO = FrontendAnalogType.AUTO;
     /**
      * PAL analog signal type.
      */
-    public static final int SIGNAL_TYPE_PAL = Constants.FrontendAnalogType.PAL;
+    public static final int SIGNAL_TYPE_PAL = FrontendAnalogType.PAL;
     /**
      * PAL M analog signal type.
      */
-    public static final int SIGNAL_TYPE_PAL_M = Constants.FrontendAnalogType.PAL_M;
+    public static final int SIGNAL_TYPE_PAL_M = FrontendAnalogType.PAL_M;
     /**
      * PAL N analog signal type.
      */
-    public static final int SIGNAL_TYPE_PAL_N = Constants.FrontendAnalogType.PAL_N;
+    public static final int SIGNAL_TYPE_PAL_N = FrontendAnalogType.PAL_N;
     /**
      * PAL 60 analog signal type.
      */
-    public static final int SIGNAL_TYPE_PAL_60 = Constants.FrontendAnalogType.PAL_60;
+    public static final int SIGNAL_TYPE_PAL_60 = FrontendAnalogType.PAL_60;
     /**
      * NTSC analog signal type.
      */
-    public static final int SIGNAL_TYPE_NTSC = Constants.FrontendAnalogType.NTSC;
+    public static final int SIGNAL_TYPE_NTSC = FrontendAnalogType.NTSC;
     /**
      * NTSC 443 analog signal type.
      */
-    public static final int SIGNAL_TYPE_NTSC_443 = Constants.FrontendAnalogType.NTSC_443;
+    public static final int SIGNAL_TYPE_NTSC_443 = FrontendAnalogType.NTSC_443;
     /**
      * SECM analog signal type.
      */
-    public static final int SIGNAL_TYPE_SECAM = Constants.FrontendAnalogType.SECAM;
+    public static final int SIGNAL_TYPE_SECAM = FrontendAnalogType.SECAM;
 
     /** @hide */
     @IntDef(flag = true,
@@ -91,79 +93,79 @@
     /**
      * Undefined Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_UNDEFINED = Constants.FrontendAnalogSifStandard.UNDEFINED;
+    public static final int SIF_UNDEFINED = FrontendAnalogSifStandard.UNDEFINED;
     /**
      * Audo Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_AUTO = Constants.FrontendAnalogSifStandard.AUTO;
+    public static final int SIF_AUTO = FrontendAnalogSifStandard.AUTO;
      /**
      * BG Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_BG = Constants.FrontendAnalogSifStandard.BG;
+    public static final int SIF_BG = FrontendAnalogSifStandard.BG;
     /**
      * BG-A2 Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_BG_A2 = Constants.FrontendAnalogSifStandard.BG_A2;
+    public static final int SIF_BG_A2 = FrontendAnalogSifStandard.BG_A2;
     /**
      * BG-NICAM Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_BG_NICAM = Constants.FrontendAnalogSifStandard.BG_NICAM;
+    public static final int SIF_BG_NICAM = FrontendAnalogSifStandard.BG_NICAM;
     /**
      * I Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_I = Constants.FrontendAnalogSifStandard.I;
+    public static final int SIF_I = FrontendAnalogSifStandard.I;
     /**
      * DK Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_DK = Constants.FrontendAnalogSifStandard.DK;
+    public static final int SIF_DK = FrontendAnalogSifStandard.DK;
     /**
      * DK1 A2 Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_DK1_A2 = Constants.FrontendAnalogSifStandard.DK1_A2;
+    public static final int SIF_DK1_A2 = FrontendAnalogSifStandard.DK1_A2;
     /**
      * DK2 A2 Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_DK2_A2 = Constants.FrontendAnalogSifStandard.DK2_A2;
+    public static final int SIF_DK2_A2 = FrontendAnalogSifStandard.DK2_A2;
     /**
      * DK3 A2 Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_DK3_A2 = Constants.FrontendAnalogSifStandard.DK3_A2;
+    public static final int SIF_DK3_A2 = FrontendAnalogSifStandard.DK3_A2;
     /**
      * DK-NICAM Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_DK_NICAM = Constants.FrontendAnalogSifStandard.DK_NICAM;
+    public static final int SIF_DK_NICAM = FrontendAnalogSifStandard.DK_NICAM;
     /**
      * L Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_L = Constants.FrontendAnalogSifStandard.L;
+    public static final int SIF_L = FrontendAnalogSifStandard.L;
     /**
      * M Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_M = Constants.FrontendAnalogSifStandard.M;
+    public static final int SIF_M = FrontendAnalogSifStandard.M;
     /**
      * M-BTSC Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_M_BTSC = Constants.FrontendAnalogSifStandard.M_BTSC;
+    public static final int SIF_M_BTSC = FrontendAnalogSifStandard.M_BTSC;
     /**
      * M-A2 Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_M_A2 = Constants.FrontendAnalogSifStandard.M_A2;
+    public static final int SIF_M_A2 = FrontendAnalogSifStandard.M_A2;
     /**
      * M-EIAJ Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_M_EIAJ = Constants.FrontendAnalogSifStandard.M_EIAJ;
+    public static final int SIF_M_EIAJ = FrontendAnalogSifStandard.M_EIAJ;
     /**
      * I-NICAM Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_I_NICAM = Constants.FrontendAnalogSifStandard.I_NICAM;
+    public static final int SIF_I_NICAM = FrontendAnalogSifStandard.I_NICAM;
     /**
      * L-NICAM Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_L_NICAM = Constants.FrontendAnalogSifStandard.L_NICAM;
+    public static final int SIF_L_NICAM = FrontendAnalogSifStandard.L_NICAM;
     /**
      * L-PRIME Analog Standard Interchange Format (SIF).
      */
-    public static final int SIF_L_PRIME = Constants.FrontendAnalogSifStandard.L_PRIME;
+    public static final int SIF_L_PRIME = FrontendAnalogSifStandard.L_PRIME;
 
     /** @hide */
     @IntDef(prefix = "AFT_FLAG_",
@@ -174,18 +176,15 @@
     /**
      * Aft flag is not defined.
      */
-    public static final int AFT_FLAG_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.UNDEFINED;
+    public static final int AFT_FLAG_UNDEFINED = FrontendAnalogAftFlag.UNDEFINED;
     /**
      * Aft flag is set true.
      */
-    public static final int AFT_FLAG_TRUE =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_TRUE;
+    public static final int AFT_FLAG_TRUE = FrontendAnalogAftFlag.AFT_TRUE;
     /**
      * Aft flag is not set.
      */
-    public static final int AFT_FLAG_FALSE =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_FALSE;
+    public static final int AFT_FLAG_FALSE = FrontendAnalogAftFlag.AFT_FALSE;
 
 
     private final int mSignalType;
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index ed1ce2d..52a20cb 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -20,7 +20,12 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendAtsc3Bandwidth;
+import android.hardware.tv.tuner.FrontendAtsc3CodeRate;
+import android.hardware.tv.tuner.FrontendAtsc3DemodOutputFormat;
+import android.hardware.tv.tuner.FrontendAtsc3Fec;
+import android.hardware.tv.tuner.FrontendAtsc3Modulation;
+import android.hardware.tv.tuner.FrontendAtsc3TimeInterleaveMode;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -44,27 +49,23 @@
     /**
      * Bandwidth not defined.
      */
-    public static final int BANDWIDTH_UNDEFINED =
-            Constants.FrontendAtsc3Bandwidth.UNDEFINED;
+    public static final int BANDWIDTH_UNDEFINED = FrontendAtsc3Bandwidth.UNDEFINED;
     /**
      * Hardware is able to detect and set bandwidth automatically
      */
-    public static final int BANDWIDTH_AUTO = Constants.FrontendAtsc3Bandwidth.AUTO;
+    public static final int BANDWIDTH_AUTO = FrontendAtsc3Bandwidth.AUTO;
     /**
      * 6 MHz bandwidth.
      */
-    public static final int BANDWIDTH_BANDWIDTH_6MHZ =
-            Constants.FrontendAtsc3Bandwidth.BANDWIDTH_6MHZ;
+    public static final int BANDWIDTH_BANDWIDTH_6MHZ = FrontendAtsc3Bandwidth.BANDWIDTH_6MHZ;
     /**
      * 7 MHz bandwidth.
      */
-    public static final int BANDWIDTH_BANDWIDTH_7MHZ =
-            Constants.FrontendAtsc3Bandwidth.BANDWIDTH_7MHZ;
+    public static final int BANDWIDTH_BANDWIDTH_7MHZ = FrontendAtsc3Bandwidth.BANDWIDTH_7MHZ;
     /**
      * 8 MHz bandwidth.
      */
-    public static final int BANDWIDTH_BANDWIDTH_8MHZ =
-            Constants.FrontendAtsc3Bandwidth.BANDWIDTH_8MHZ;
+    public static final int BANDWIDTH_BANDWIDTH_8MHZ = FrontendAtsc3Bandwidth.BANDWIDTH_8MHZ;
 
 
     /** @hide */
@@ -80,35 +81,35 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendAtsc3Modulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendAtsc3Modulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically.
      */
-    public static final int MODULATION_AUTO = Constants.FrontendAtsc3Modulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendAtsc3Modulation.AUTO;
     /**
      * QPSK modulation.
      */
-    public static final int MODULATION_MOD_QPSK = Constants.FrontendAtsc3Modulation.MOD_QPSK;
+    public static final int MODULATION_MOD_QPSK = FrontendAtsc3Modulation.MOD_QPSK;
     /**
      * 16QAM modulation.
      */
-    public static final int MODULATION_MOD_16QAM = Constants.FrontendAtsc3Modulation.MOD_16QAM;
+    public static final int MODULATION_MOD_16QAM = FrontendAtsc3Modulation.MOD_16QAM;
     /**
      * 64QAM modulation.
      */
-    public static final int MODULATION_MOD_64QAM = Constants.FrontendAtsc3Modulation.MOD_64QAM;
+    public static final int MODULATION_MOD_64QAM = FrontendAtsc3Modulation.MOD_64QAM;
     /**
      * 256QAM modulation.
      */
-    public static final int MODULATION_MOD_256QAM = Constants.FrontendAtsc3Modulation.MOD_256QAM;
+    public static final int MODULATION_MOD_256QAM = FrontendAtsc3Modulation.MOD_256QAM;
     /**
      * 1024QAM modulation.
      */
-    public static final int MODULATION_MOD_1024QAM = Constants.FrontendAtsc3Modulation.MOD_1024QAM;
+    public static final int MODULATION_MOD_1024QAM = FrontendAtsc3Modulation.MOD_1024QAM;
     /**
      * 4096QAM modulation.
      */
-    public static final int MODULATION_MOD_4096QAM = Constants.FrontendAtsc3Modulation.MOD_4096QAM;
+    public static final int MODULATION_MOD_4096QAM = FrontendAtsc3Modulation.MOD_4096QAM;
 
 
     /** @hide */
@@ -123,22 +124,19 @@
      * Time interleave mode undefined.
      */
     public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
-            Constants.FrontendAtsc3TimeInterleaveMode.UNDEFINED;
+            FrontendAtsc3TimeInterleaveMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Time Interleave Mode automatically.
      */
-    public static final int TIME_INTERLEAVE_MODE_AUTO =
-            Constants.FrontendAtsc3TimeInterleaveMode.AUTO;
+    public static final int TIME_INTERLEAVE_MODE_AUTO = FrontendAtsc3TimeInterleaveMode.AUTO;
     /**
      * CTI Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_CTI =
-            Constants.FrontendAtsc3TimeInterleaveMode.CTI;
+    public static final int TIME_INTERLEAVE_MODE_CTI = FrontendAtsc3TimeInterleaveMode.CTI;
     /**
      * HTI Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_HTI =
-            Constants.FrontendAtsc3TimeInterleaveMode.HTI;
+    public static final int TIME_INTERLEAVE_MODE_HTI = FrontendAtsc3TimeInterleaveMode.HTI;
 
 
     /** @hide */
@@ -153,59 +151,59 @@
     /**
      * Code rate undefined.
      */
-    public static final int CODERATE_UNDEFINED = Constants.FrontendAtsc3CodeRate.UNDEFINED;
+    public static final int CODERATE_UNDEFINED = FrontendAtsc3CodeRate.UNDEFINED;
     /**
      * Hardware is able to detect and set code rate automatically
      */
-    public static final int CODERATE_AUTO = Constants.FrontendAtsc3CodeRate.AUTO;
+    public static final int CODERATE_AUTO = FrontendAtsc3CodeRate.AUTO;
     /**
      * 2/15 code rate.
      */
-    public static final int CODERATE_2_15 = Constants.FrontendAtsc3CodeRate.CODERATE_2_15;
+    public static final int CODERATE_2_15 = FrontendAtsc3CodeRate.CODERATE_2_15;
     /**
      * 3/15 code rate.
      */
-    public static final int CODERATE_3_15 = Constants.FrontendAtsc3CodeRate.CODERATE_3_15;
+    public static final int CODERATE_3_15 = FrontendAtsc3CodeRate.CODERATE_3_15;
     /**
      * 4/15 code rate.
      */
-    public static final int CODERATE_4_15 = Constants.FrontendAtsc3CodeRate.CODERATE_4_15;
+    public static final int CODERATE_4_15 = FrontendAtsc3CodeRate.CODERATE_4_15;
     /**
      * 5/15 code rate.
      */
-    public static final int CODERATE_5_15 = Constants.FrontendAtsc3CodeRate.CODERATE_5_15;
+    public static final int CODERATE_5_15 = FrontendAtsc3CodeRate.CODERATE_5_15;
     /**
      * 6/15 code rate.
      */
-    public static final int CODERATE_6_15 = Constants.FrontendAtsc3CodeRate.CODERATE_6_15;
+    public static final int CODERATE_6_15 = FrontendAtsc3CodeRate.CODERATE_6_15;
     /**
      * 7/15 code rate.
      */
-    public static final int CODERATE_7_15 = Constants.FrontendAtsc3CodeRate.CODERATE_7_15;
+    public static final int CODERATE_7_15 = FrontendAtsc3CodeRate.CODERATE_7_15;
     /**
      * 8/15 code rate.
      */
-    public static final int CODERATE_8_15 = Constants.FrontendAtsc3CodeRate.CODERATE_8_15;
+    public static final int CODERATE_8_15 = FrontendAtsc3CodeRate.CODERATE_8_15;
     /**
      * 9/15 code rate.
      */
-    public static final int CODERATE_9_15 = Constants.FrontendAtsc3CodeRate.CODERATE_9_15;
+    public static final int CODERATE_9_15 = FrontendAtsc3CodeRate.CODERATE_9_15;
     /**
      * 10/15 code rate.
      */
-    public static final int CODERATE_10_15 = Constants.FrontendAtsc3CodeRate.CODERATE_10_15;
+    public static final int CODERATE_10_15 = FrontendAtsc3CodeRate.CODERATE_10_15;
     /**
      * 11/15 code rate.
      */
-    public static final int CODERATE_11_15 = Constants.FrontendAtsc3CodeRate.CODERATE_11_15;
+    public static final int CODERATE_11_15 = FrontendAtsc3CodeRate.CODERATE_11_15;
     /**
      * 12/15 code rate.
      */
-    public static final int CODERATE_12_15 = Constants.FrontendAtsc3CodeRate.CODERATE_12_15;
+    public static final int CODERATE_12_15 = FrontendAtsc3CodeRate.CODERATE_12_15;
     /**
      * 13/15 code rate.
      */
-    public static final int CODERATE_13_15 = Constants.FrontendAtsc3CodeRate.CODERATE_13_15;
+    public static final int CODERATE_13_15 = FrontendAtsc3CodeRate.CODERATE_13_15;
 
 
     /** @hide */
@@ -219,35 +217,35 @@
     /**
      * Forward Error Correction undefined.
      */
-    public static final int FEC_UNDEFINED = Constants.FrontendAtsc3Fec.UNDEFINED;
+    public static final int FEC_UNDEFINED = FrontendAtsc3Fec.UNDEFINED;
     /**
      * Hardware is able to detect and set FEC automatically
      */
-    public static final int FEC_AUTO = Constants.FrontendAtsc3Fec.AUTO;
+    public static final int FEC_AUTO = FrontendAtsc3Fec.AUTO;
     /**
      * BCH LDPC 16K Forward Error Correction
      */
-    public static final int FEC_BCH_LDPC_16K = Constants.FrontendAtsc3Fec.BCH_LDPC_16K;
+    public static final int FEC_BCH_LDPC_16K = FrontendAtsc3Fec.BCH_LDPC_16K;
     /**
      * BCH LDPC 64K Forward Error Correction
      */
-    public static final int FEC_BCH_LDPC_64K = Constants.FrontendAtsc3Fec.BCH_LDPC_64K;
+    public static final int FEC_BCH_LDPC_64K = FrontendAtsc3Fec.BCH_LDPC_64K;
     /**
      * CRC LDPC 16K Forward Error Correction
      */
-    public static final int FEC_CRC_LDPC_16K = Constants.FrontendAtsc3Fec.CRC_LDPC_16K;
+    public static final int FEC_CRC_LDPC_16K = FrontendAtsc3Fec.CRC_LDPC_16K;
     /**
      * CRC LDPC 64K Forward Error Correction
      */
-    public static final int FEC_CRC_LDPC_64K = Constants.FrontendAtsc3Fec.CRC_LDPC_64K;
+    public static final int FEC_CRC_LDPC_64K = FrontendAtsc3Fec.CRC_LDPC_64K;
     /**
      * LDPC 16K Forward Error Correction
      */
-    public static final int FEC_LDPC_16K = Constants.FrontendAtsc3Fec.LDPC_16K;
+    public static final int FEC_LDPC_16K = FrontendAtsc3Fec.LDPC_16K;
     /**
      * LDPC 64K Forward Error Correction
      */
-    public static final int FEC_LDPC_64K = Constants.FrontendAtsc3Fec.LDPC_64K;
+    public static final int FEC_LDPC_64K = FrontendAtsc3Fec.LDPC_64K;
 
 
     /** @hide */
@@ -262,17 +260,17 @@
      * Demod output format undefined.
      */
     public static final int DEMOD_OUTPUT_FORMAT_UNDEFINED =
-            Constants.FrontendAtsc3DemodOutputFormat.UNDEFINED;
+            FrontendAtsc3DemodOutputFormat.UNDEFINED;
     /**
      * ALP format. Typically used in US region.
      */
     public static final int DEMOD_OUTPUT_FORMAT_ATSC3_LINKLAYER_PACKET =
-            Constants.FrontendAtsc3DemodOutputFormat.ATSC3_LINKLAYER_PACKET;
+            FrontendAtsc3DemodOutputFormat.ATSC3_LINKLAYER_PACKET;
     /**
      * BaseBand packet format. Typically used in Korea region.
      */
     public static final int DEMOD_OUTPUT_FORMAT_BASEBAND_PACKET =
-            Constants.FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET;
+            FrontendAtsc3DemodOutputFormat.BASEBAND_PACKET;
 
     private final int mBandwidth;
     private final int mDemodOutputFormat;
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index f7244bb..042bba8 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
@@ -20,7 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendAtscModulation;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -44,19 +44,19 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendAtscModulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendAtscModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically
      */
-    public static final int MODULATION_AUTO = Constants.FrontendAtscModulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendAtscModulation.AUTO;
     /**
      * 8VSB Modulation.
      */
-    public static final int MODULATION_MOD_8VSB = Constants.FrontendAtscModulation.MOD_8VSB;
+    public static final int MODULATION_MOD_8VSB = FrontendAtscModulation.MOD_8VSB;
     /**
      * 16VSB Modulation.
      */
-    public static final int MODULATION_MOD_16VSB = Constants.FrontendAtscModulation.MOD_16VSB;
+    public static final int MODULATION_MOD_16VSB = FrontendAtscModulation.MOD_16VSB;
 
 
     private final int mModulation;
diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
index c1d0833..9ba41d5 100644
--- a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
@@ -21,6 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.hardware.tv.tuner.FrontendDtmbBandwidth;
+import android.hardware.tv.tuner.FrontendDtmbCodeRate;
+import android.hardware.tv.tuner.FrontendDtmbGuardInterval;
+import android.hardware.tv.tuner.FrontendDtmbModulation;
+import android.hardware.tv.tuner.FrontendDtmbTimeInterleaveMode;
+import android.hardware.tv.tuner.FrontendDtmbTransmissionMode;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -46,23 +52,19 @@
     /**
      * Bandwidth not defined.
      */
-    public static final int BANDWIDTH_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.UNDEFINED;
+    public static final int BANDWIDTH_UNDEFINED = FrontendDtmbBandwidth.UNDEFINED;
     /**
      * Hardware is able to detect and set bandwidth automatically
      */
-    public static final int BANDWIDTH_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.AUTO;
+    public static final int BANDWIDTH_AUTO = FrontendDtmbBandwidth.AUTO;
     /**
      * 6 MHz bandwidth.
      */
-    public static final int BANDWIDTH_6MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.BANDWIDTH_6MHZ;
+    public static final int BANDWIDTH_6MHZ = FrontendDtmbBandwidth.BANDWIDTH_6MHZ;
     /**
      * 8 MHz bandwidth.
      */
-    public static final int BANDWIDTH_8MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbBandwidth.BANDWIDTH_8MHZ;
+    public static final int BANDWIDTH_8MHZ = FrontendDtmbBandwidth.BANDWIDTH_8MHZ;
 
 
     /** @hide */
@@ -77,22 +79,21 @@
      * Time Interleave Mode undefined.
      */
     public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.UNDEFINED;
+            FrontendDtmbTimeInterleaveMode.UNDEFINED;
     /**
      * Hardware is able to detect and set time interleave mode automatically
      */
-    public static final int TIME_INTERLEAVE_MODE_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.AUTO;
+    public static final int TIME_INTERLEAVE_MODE_AUTO = FrontendDtmbTimeInterleaveMode.AUTO;
     /**
      * Time Interleave Mode timer int 240.
      */
     public static final int TIME_INTERLEAVE_MODE_TIMER_INT_240 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.TIMER_INT_240;
+            FrontendDtmbTimeInterleaveMode.TIMER_INT_240;
     /**
      * Time Interleave Mode timer int 720.
      */
     public static final int TIME_INTERLEAVE_MODE_TIMER_INT_720 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTimeInterleaveMode.TIMER_INT_720;
+            FrontendDtmbTimeInterleaveMode.TIMER_INT_720;
 
 
     /** @hide */
@@ -108,43 +109,37 @@
     /**
      * Guard Interval undefined.
      */
-    public static final int GUARD_INTERVAL_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.UNDEFINED;
+    public static final int GUARD_INTERVAL_UNDEFINED = FrontendDtmbGuardInterval.UNDEFINED;
     /**
      * Hardware is able to detect and set Guard Interval automatically.
      */
-    public static final int GUARD_INTERVAL_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.AUTO;
+    public static final int GUARD_INTERVAL_AUTO = FrontendDtmbGuardInterval.AUTO;
     /**
      * PN_420_VARIOUS Guard Interval.
      */
     public static final int GUARD_INTERVAL_PN_420_VARIOUS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_420_VARIOUS;
+            FrontendDtmbGuardInterval.PN_420_VARIOUS;
     /**
      * PN_595_CONST Guard Interval.
      */
-    public static final int GUARD_INTERVAL_PN_595_CONST =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_595_CONST;
+    public static final int GUARD_INTERVAL_PN_595_CONST = FrontendDtmbGuardInterval.PN_595_CONST;
     /**
      * PN_945_VARIOUS Guard Interval.
      */
     public static final int GUARD_INTERVAL_PN_945_VARIOUS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_945_VARIOUS;
+            FrontendDtmbGuardInterval.PN_945_VARIOUS;
     /**
      * PN_420_CONST Guard Interval.
      */
-    public static final int GUARD_INTERVAL_PN_420_CONST =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_420_CONST;
+    public static final int GUARD_INTERVAL_PN_420_CONST = FrontendDtmbGuardInterval.PN_420_CONST;
     /**
      * PN_945_CONST Guard Interval.
      */
-    public static final int GUARD_INTERVAL_PN_945_CONST =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_945_CONST;
+    public static final int GUARD_INTERVAL_PN_945_CONST = FrontendDtmbGuardInterval.PN_945_CONST;
     /**
      * PN_RESERVED Guard Interval.
      */
-    public static final int GUARD_INTERVAL_PN_RESERVED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbGuardInterval.PN_RESERVED;
+    public static final int GUARD_INTERVAL_PN_RESERVED = FrontendDtmbGuardInterval.PN_RESERVED;
 
 
     /** @hide */
@@ -160,38 +155,36 @@
     /**
      * Constellation not defined.
      */
-    public static final int MODULATION_CONSTELLATION_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.UNDEFINED;
+    public static final int MODULATION_CONSTELLATION_UNDEFINED = FrontendDtmbModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set Constellation automatically.
      */
-    public static final int MODULATION_CONSTELLATION_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.AUTO;
+    public static final int MODULATION_CONSTELLATION_AUTO = FrontendDtmbModulation.AUTO;
     /**
      * 4QAM Constellation.
      */
     public static final int MODULATION_CONSTELLATION_4QAM =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_4QAM;
+            FrontendDtmbModulation.CONSTELLATION_4QAM;
     /**
      * 4QAM_NR Constellation.
      */
     public static final int MODULATION_CONSTELLATION_4QAM_NR =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_4QAM_NR;
+            FrontendDtmbModulation.CONSTELLATION_4QAM_NR;
     /**
      * 16QAM Constellation.
      */
     public static final int MODULATION_CONSTELLATION_16QAM =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_16QAM;
+            FrontendDtmbModulation.CONSTELLATION_16QAM;
     /**
      * 32QAM Constellation.
      */
     public static final int MODULATION_CONSTELLATION_32QAM =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_32QAM;
+            FrontendDtmbModulation.CONSTELLATION_32QAM;
     /**
      * 64QAM Constellation.
      */
     public static final int MODULATION_CONSTELLATION_64QAM =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbModulation.CONSTELLATION_64QAM;
+            FrontendDtmbModulation.CONSTELLATION_64QAM;
 
     /** @hide */
     @IntDef(flag = true,
@@ -203,28 +196,23 @@
     /**
      * Code rate undefined.
      */
-    public static final int CODERATE_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.UNDEFINED;
+    public static final int CODERATE_UNDEFINED = FrontendDtmbCodeRate.UNDEFINED;
     /**
      * Hardware is able to detect and set code rate automatically.
      */
-    public static final int CODERATE_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.AUTO;
+    public static final int CODERATE_AUTO = FrontendDtmbCodeRate.AUTO;
     /**
      * 2/5 code rate.
      */
-    public static final int CODERATE_2_5 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_2_5;
+    public static final int CODERATE_2_5 = FrontendDtmbCodeRate.CODERATE_2_5;
     /**
      * 3/5 code rate.
      */
-    public static final int CODERATE_3_5 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_3_5;
+    public static final int CODERATE_3_5 = FrontendDtmbCodeRate.CODERATE_3_5;
     /**
      * 4/5 code rate.
      */
-    public static final int CODERATE_4_5 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbCodeRate.CODERATE_4_5;
+    public static final int CODERATE_4_5 = FrontendDtmbCodeRate.CODERATE_4_5;
 
     /** @hide */
     @IntDef(flag = true,
@@ -237,23 +225,19 @@
     /**
      * Transmission Mode undefined.
      */
-    public static final int TRANSMISSION_MODE_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.UNDEFINED;
+    public static final int TRANSMISSION_MODE_UNDEFINED = FrontendDtmbTransmissionMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Transmission Mode automatically
      */
-    public static final int TRANSMISSION_MODE_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.AUTO;
+    public static final int TRANSMISSION_MODE_AUTO = FrontendDtmbTransmissionMode.AUTO;
     /**
      * C1 Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_C1 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.C1;
+    public static final int TRANSMISSION_MODE_C1 = FrontendDtmbTransmissionMode.C1;
     /**
      * C3780 Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_C3780 =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDtmbTransmissionMode.C3780;
+    public static final int TRANSMISSION_MODE_C3780 = FrontendDtmbTransmissionMode.C3780;
 
 
     private final int mModulation;
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index db28631..b209d97 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -20,7 +20,11 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendCableTimeInterleaveMode;
+import android.hardware.tv.tuner.FrontendDvbcAnnex;
+import android.hardware.tv.tuner.FrontendDvbcBandwidth;
+import android.hardware.tv.tuner.FrontendDvbcModulation;
+import android.hardware.tv.tuner.FrontendDvbcOuterFec;
 import android.media.tv.tuner.TunerVersionChecker;
 import android.media.tv.tuner.frontend.FrontendSettings.FrontendSpectralInversion;
 
@@ -47,31 +51,31 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendDvbcModulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendDvbcModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically
      */
-    public static final int MODULATION_AUTO = Constants.FrontendDvbcModulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendDvbcModulation.AUTO;
     /**
      * 16QAM Modulation.
      */
-    public static final int MODULATION_MOD_16QAM = Constants.FrontendDvbcModulation.MOD_16QAM;
+    public static final int MODULATION_MOD_16QAM = FrontendDvbcModulation.MOD_16QAM;
     /**
      * 32QAM Modulation.
      */
-    public static final int MODULATION_MOD_32QAM = Constants.FrontendDvbcModulation.MOD_32QAM;
+    public static final int MODULATION_MOD_32QAM = FrontendDvbcModulation.MOD_32QAM;
     /**
      * 64QAM Modulation.
      */
-    public static final int MODULATION_MOD_64QAM = Constants.FrontendDvbcModulation.MOD_64QAM;
+    public static final int MODULATION_MOD_64QAM = FrontendDvbcModulation.MOD_64QAM;
     /**
      * 128QAM Modulation.
      */
-    public static final int MODULATION_MOD_128QAM = Constants.FrontendDvbcModulation.MOD_128QAM;
+    public static final int MODULATION_MOD_128QAM = FrontendDvbcModulation.MOD_128QAM;
     /**
      * 256QAM Modulation.
      */
-    public static final int MODULATION_MOD_256QAM = Constants.FrontendDvbcModulation.MOD_256QAM;
+    public static final int MODULATION_MOD_256QAM = FrontendDvbcModulation.MOD_256QAM;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -82,16 +86,15 @@
     /**
      * Outer Forward Error Correction (FEC) Type undefined.
      */
-    public static final int OUTER_FEC_UNDEFINED = Constants.FrontendDvbcOuterFec.UNDEFINED;
+    public static final int OUTER_FEC_UNDEFINED = FrontendDvbcOuterFec.UNDEFINED;
     /**
      * None Outer Forward Error Correction (FEC) Type.
      */
-    public static final int OUTER_FEC_OUTER_FEC_NONE =
-            Constants.FrontendDvbcOuterFec.OUTER_FEC_NONE;
+    public static final int OUTER_FEC_OUTER_FEC_NONE = FrontendDvbcOuterFec.OUTER_FEC_NONE;
     /**
      * RS Outer Forward Error Correction (FEC) Type.
      */
-    public static final int OUTER_FEC_OUTER_FEC_RS = Constants.FrontendDvbcOuterFec.OUTER_FEC_RS;
+    public static final int OUTER_FEC_OUTER_FEC_RS = FrontendDvbcOuterFec.OUTER_FEC_RS;
 
 
     /** @hide */
@@ -104,19 +107,19 @@
     /**
      * Annex Type undefined.
      */
-    public static final int ANNEX_UNDEFINED = Constants.FrontendDvbcAnnex.UNDEFINED;
+    public static final int ANNEX_UNDEFINED = FrontendDvbcAnnex.UNDEFINED;
     /**
      * Annex Type A.
      */
-    public static final int ANNEX_A = Constants.FrontendDvbcAnnex.A;
+    public static final int ANNEX_A = FrontendDvbcAnnex.A;
     /**
      * Annex Type B.
      */
-    public static final int ANNEX_B = Constants.FrontendDvbcAnnex.B;
+    public static final int ANNEX_B = FrontendDvbcAnnex.B;
     /**
      * Annex Type C.
      */
-    public static final int ANNEX_C = Constants.FrontendDvbcAnnex.C;
+    public static final int ANNEX_C = FrontendDvbcAnnex.C;
 
 
     /**
@@ -137,7 +140,7 @@
      */
     @Deprecated
     public static final int SPECTRAL_INVERSION_UNDEFINED =
-            Constants.FrontendDvbcSpectralInversion.UNDEFINED;
+            android.hardware.tv.tuner.FrontendSpectralInversion.UNDEFINED;
     /**
      * Normal Spectral Inversion.
      *
@@ -145,7 +148,7 @@
      */
     @Deprecated
     public static final int SPECTRAL_INVERSION_NORMAL =
-            Constants.FrontendDvbcSpectralInversion.NORMAL;
+             android.hardware.tv.tuner.FrontendSpectralInversion.NORMAL;
     /**
      * Inverted Spectral Inversion.
      *
@@ -153,7 +156,7 @@
      */
     @Deprecated
     public static final int SPECTRAL_INVERSION_INVERTED =
-            Constants.FrontendDvbcSpectralInversion.INVERTED;
+            android.hardware.tv.tuner.FrontendSpectralInversion.INVERTED;
 
     /** @hide */
     @IntDef(flag = true,
@@ -171,57 +174,56 @@
      * Time interleave mode undefined.
      */
     public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.UNDEFINED;
+            FrontendCableTimeInterleaveMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Time Interleave Mode automatically.
      */
-    public static final int TIME_INTERLEAVE_MODE_AUTO =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.AUTO;
+    public static final int TIME_INTERLEAVE_MODE_AUTO = FrontendCableTimeInterleaveMode.AUTO;
     /**
      * 128/1/0 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_128_1_0 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_0;
+    public static final int TIME_INTERLEAVE_MODE_128_1_0 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_0;
     /**
      * 128/1/1 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_128_1_1 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_1;
+    public static final int TIME_INTERLEAVE_MODE_128_1_1 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_1;
     /**
      * 64/2 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_64_2 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_64_2;
+    public static final int TIME_INTERLEAVE_MODE_64_2 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_64_2;
     /**
      * 32/4 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_32_4 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_32_4;
+    public static final int TIME_INTERLEAVE_MODE_32_4 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_32_4;
     /**
      * 16/8 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_16_8 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_16_8;
+    public static final int TIME_INTERLEAVE_MODE_16_8 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_16_8;
     /**
      * 8/16 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_8_16 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_8_16;
+    public static final int TIME_INTERLEAVE_MODE_8_16 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_8_16;
     /**
      * 128/2 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_128_2 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_128_2;
+    public static final int TIME_INTERLEAVE_MODE_128_2 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_128_2;
     /**
      * 128/3 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_128_3 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_128_3;
+    public static final int TIME_INTERLEAVE_MODE_128_3 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_128_3;
     /**
      * 128/4 Time Interleave Mode.
      */
-    public static final int TIME_INTERLEAVE_MODE_128_4 = android.hardware.tv.tuner.V1_1.Constants
-            .FrontendCableTimeInterleaveMode.INTERLEAVING_128_4;
+    public static final int TIME_INTERLEAVE_MODE_128_4 =
+            FrontendCableTimeInterleaveMode.INTERLEAVING_128_4;
 
     /** @hide */
     @IntDef(flag = true,
@@ -234,28 +236,23 @@
     /**
      * Bandwidth undefined.
      */
-    public static final int BANDWIDTH_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbcBandwidth.UNDEFINED;
+    public static final int BANDWIDTH_UNDEFINED = FrontendDvbcBandwidth.UNDEFINED;
     /**
      * 5 MHz bandwidth.
      */
-    public static final int BANDWIDTH_5MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbcBandwidth.BANDWIDTH_5MHZ;
+    public static final int BANDWIDTH_5MHZ = FrontendDvbcBandwidth.BANDWIDTH_5MHZ;
     /**
      * 6 MHz bandwidth.
      */
-    public static final int BANDWIDTH_6MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbcBandwidth.BANDWIDTH_6MHZ;
+    public static final int BANDWIDTH_6MHZ = FrontendDvbcBandwidth.BANDWIDTH_6MHZ;
     /**
      * 7 MHz bandwidth.
      */
-    public static final int BANDWIDTH_7MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbcBandwidth.BANDWIDTH_7MHZ;
+    public static final int BANDWIDTH_7MHZ = FrontendDvbcBandwidth.BANDWIDTH_7MHZ;
     /**
      * 8 MHz bandwidth.
      */
-    public static final int BANDWIDTH_8MHZ =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbcBandwidth.BANDWIDTH_8MHZ;
+    public static final int BANDWIDTH_8MHZ = FrontendDvbcBandwidth.BANDWIDTH_8MHZ;
 
 
     private final int mModulation;
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index f68d554..6e3d98a 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -21,7 +21,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendDvbsModulation;
+import android.hardware.tv.tuner.FrontendDvbsPilot;
+import android.hardware.tv.tuner.FrontendDvbsRolloff;
+import android.hardware.tv.tuner.FrontendDvbsScanType;
+import android.hardware.tv.tuner.FrontendDvbsStandard;
+import android.hardware.tv.tuner.FrontendDvbsVcmMode;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerVersionChecker;
 
@@ -47,32 +52,27 @@
     /**
      * Dvbs scan type undefined.
      */
-    public static final int SCAN_TYPE_UNDEFINED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNDEFINED;
+    public static final int SCAN_TYPE_UNDEFINED = FrontendDvbsScanType.UNDEFINED;
 
     /**
      * Dvbs scan type DIRECT.
      */
-    public static final int SCAN_TYPE_DIRECT =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DIRECT;
+    public static final int SCAN_TYPE_DIRECT = FrontendDvbsScanType.DIRECT;
 
     /**
      * Dvbs scan type DISEQC.
      */
-    public static final int SCAN_TYPE_DISEQC =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DISEQC;
+    public static final int SCAN_TYPE_DISEQC = FrontendDvbsScanType.DISEQC;
 
     /**
      * Dvbs scan type UNICABLE.
      */
-    public static final int SCAN_TYPE_UNICABLE =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNICABLE;
+    public static final int SCAN_TYPE_UNICABLE = FrontendDvbsScanType.UNICABLE;
 
     /**
      * Dvbs scan type JESS.
      */
-    public static final int SCAN_TYPE_JESS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.JESS;
+    public static final int SCAN_TYPE_JESS = FrontendDvbsScanType.JESS;
 
     /** @hide */
     @IntDef(flag = true,
@@ -88,63 +88,63 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendDvbsModulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendDvbsModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically
      */
-    public static final int MODULATION_AUTO = Constants.FrontendDvbsModulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendDvbsModulation.AUTO;
     /**
      * QPSK Modulation.
      */
-    public static final int MODULATION_MOD_QPSK = Constants.FrontendDvbsModulation.MOD_QPSK;
+    public static final int MODULATION_MOD_QPSK = FrontendDvbsModulation.MOD_QPSK;
     /**
      * 8PSK Modulation.
      */
-    public static final int MODULATION_MOD_8PSK = Constants.FrontendDvbsModulation.MOD_8PSK;
+    public static final int MODULATION_MOD_8PSK = FrontendDvbsModulation.MOD_8PSK;
     /**
      * 16QAM Modulation.
      */
-    public static final int MODULATION_MOD_16QAM = Constants.FrontendDvbsModulation.MOD_16QAM;
+    public static final int MODULATION_MOD_16QAM = FrontendDvbsModulation.MOD_16QAM;
     /**
      * 16PSK Modulation.
      */
-    public static final int MODULATION_MOD_16PSK = Constants.FrontendDvbsModulation.MOD_16PSK;
+    public static final int MODULATION_MOD_16PSK = FrontendDvbsModulation.MOD_16PSK;
     /**
      * 32PSK Modulation.
      */
-    public static final int MODULATION_MOD_32PSK = Constants.FrontendDvbsModulation.MOD_32PSK;
+    public static final int MODULATION_MOD_32PSK = FrontendDvbsModulation.MOD_32PSK;
     /**
      * ACM Modulation.
      */
-    public static final int MODULATION_MOD_ACM = Constants.FrontendDvbsModulation.MOD_ACM;
+    public static final int MODULATION_MOD_ACM = FrontendDvbsModulation.MOD_ACM;
     /**
      * 8APSK Modulation.
      */
-    public static final int MODULATION_MOD_8APSK = Constants.FrontendDvbsModulation.MOD_8APSK;
+    public static final int MODULATION_MOD_8APSK = FrontendDvbsModulation.MOD_8APSK;
     /**
      * 16APSK Modulation.
      */
-    public static final int MODULATION_MOD_16APSK = Constants.FrontendDvbsModulation.MOD_16APSK;
+    public static final int MODULATION_MOD_16APSK = FrontendDvbsModulation.MOD_16APSK;
     /**
      * 32APSK Modulation.
      */
-    public static final int MODULATION_MOD_32APSK = Constants.FrontendDvbsModulation.MOD_32APSK;
+    public static final int MODULATION_MOD_32APSK = FrontendDvbsModulation.MOD_32APSK;
     /**
      * 64APSK Modulation.
      */
-    public static final int MODULATION_MOD_64APSK = Constants.FrontendDvbsModulation.MOD_64APSK;
+    public static final int MODULATION_MOD_64APSK = FrontendDvbsModulation.MOD_64APSK;
     /**
      * 128APSK Modulation.
      */
-    public static final int MODULATION_MOD_128APSK = Constants.FrontendDvbsModulation.MOD_128APSK;
+    public static final int MODULATION_MOD_128APSK = FrontendDvbsModulation.MOD_128APSK;
     /**
      * 256APSK Modulation.
      */
-    public static final int MODULATION_MOD_256APSK = Constants.FrontendDvbsModulation.MOD_256APSK;
+    public static final int MODULATION_MOD_256APSK = FrontendDvbsModulation.MOD_256APSK;
     /**
      * Reversed Modulation.
      */
-    public static final int MODULATION_MOD_RESERVED = Constants.FrontendDvbsModulation.MOD_RESERVED;
+    public static final int MODULATION_MOD_RESERVED = FrontendDvbsModulation.MOD_RESERVED;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -156,31 +156,31 @@
     /**
      * Rolloff range undefined.
      */
-    public static final int ROLLOFF_UNDEFINED = Constants.FrontendDvbsRolloff.UNDEFINED;
+    public static final int ROLLOFF_UNDEFINED = FrontendDvbsRolloff.UNDEFINED;
     /**
      * Rolloff range 0,35.
      */
-    public static final int ROLLOFF_0_35 = Constants.FrontendDvbsRolloff.ROLLOFF_0_35;
+    public static final int ROLLOFF_0_35 = FrontendDvbsRolloff.ROLLOFF_0_35;
     /**
      * Rolloff range 0,25.
      */
-    public static final int ROLLOFF_0_25 = Constants.FrontendDvbsRolloff.ROLLOFF_0_25;
+    public static final int ROLLOFF_0_25 = FrontendDvbsRolloff.ROLLOFF_0_25;
     /**
      * Rolloff range 0,20.
      */
-    public static final int ROLLOFF_0_20 = Constants.FrontendDvbsRolloff.ROLLOFF_0_20;
+    public static final int ROLLOFF_0_20 = FrontendDvbsRolloff.ROLLOFF_0_20;
     /**
      * Rolloff range 0,15.
      */
-    public static final int ROLLOFF_0_15 = Constants.FrontendDvbsRolloff.ROLLOFF_0_15;
+    public static final int ROLLOFF_0_15 = FrontendDvbsRolloff.ROLLOFF_0_15;
     /**
      * Rolloff range 0,10.
      */
-    public static final int ROLLOFF_0_10 = Constants.FrontendDvbsRolloff.ROLLOFF_0_10;
+    public static final int ROLLOFF_0_10 = FrontendDvbsRolloff.ROLLOFF_0_10;
     /**
      * Rolloff range 0,5.
      */
-    public static final int ROLLOFF_0_5 = Constants.FrontendDvbsRolloff.ROLLOFF_0_5;
+    public static final int ROLLOFF_0_5 = FrontendDvbsRolloff.ROLLOFF_0_5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -191,19 +191,19 @@
     /**
      * Pilot mode undefined.
      */
-    public static final int PILOT_UNDEFINED = Constants.FrontendDvbsPilot.UNDEFINED;
+    public static final int PILOT_UNDEFINED = FrontendDvbsPilot.UNDEFINED;
     /**
      * Pilot mode on.
      */
-    public static final int PILOT_ON = Constants.FrontendDvbsPilot.ON;
+    public static final int PILOT_ON = FrontendDvbsPilot.ON;
     /**
      * Pilot mode off.
      */
-    public static final int PILOT_OFF = Constants.FrontendDvbsPilot.OFF;
+    public static final int PILOT_OFF = FrontendDvbsPilot.OFF;
     /**
      * Pilot mode auto.
      */
-    public static final int PILOT_AUTO = Constants.FrontendDvbsPilot.AUTO;
+    public static final int PILOT_AUTO = FrontendDvbsPilot.AUTO;
 
 
     /** @hide */
@@ -216,19 +216,19 @@
     /**
      * Standard undefined.
      */
-    public static final int STANDARD_AUTO = Constants.FrontendDvbsStandard.AUTO;
+    public static final int STANDARD_AUTO = FrontendDvbsStandard.AUTO;
     /**
      * Standard S.
      */
-    public static final int STANDARD_S = Constants.FrontendDvbsStandard.S;
+    public static final int STANDARD_S = FrontendDvbsStandard.S;
     /**
      * Standard S2.
      */
-    public static final int STANDARD_S2 = Constants.FrontendDvbsStandard.S2;
+    public static final int STANDARD_S2 = FrontendDvbsStandard.S2;
     /**
      * Standard S2X.
      */
-    public static final int STANDARD_S2X = Constants.FrontendDvbsStandard.S2X;
+    public static final int STANDARD_S2X = FrontendDvbsStandard.S2X;
 
     /** @hide */
     @IntDef(prefix = "VCM_MODE_",
@@ -239,15 +239,15 @@
     /**
      * VCM mode undefined.
      */
-    public static final int VCM_MODE_UNDEFINED = Constants.FrontendDvbsVcmMode.UNDEFINED;
+    public static final int VCM_MODE_UNDEFINED = FrontendDvbsVcmMode.UNDEFINED;
     /**
      * Auto VCM mode.
      */
-    public static final int VCM_MODE_AUTO = Constants.FrontendDvbsVcmMode.AUTO;
+    public static final int VCM_MODE_AUTO = FrontendDvbsVcmMode.AUTO;
     /**
      * Manual VCM mode.
      */
-    public static final int VCM_MODE_MANUAL = Constants.FrontendDvbsVcmMode.MANUAL;
+    public static final int VCM_MODE_MANUAL = FrontendDvbsVcmMode.MANUAL;
 
 
     private final int mModulation;
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 536c7b8..5735b39 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -20,7 +20,14 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendDvbtBandwidth;
+import android.hardware.tv.tuner.FrontendDvbtCoderate;
+import android.hardware.tv.tuner.FrontendDvbtConstellation;
+import android.hardware.tv.tuner.FrontendDvbtGuardInterval;
+import android.hardware.tv.tuner.FrontendDvbtHierarchy;
+import android.hardware.tv.tuner.FrontendDvbtPlpMode;
+import android.hardware.tv.tuner.FrontendDvbtStandard;
+import android.hardware.tv.tuner.FrontendDvbtTransmissionMode;
 import android.media.tv.tuner.TunerVersionChecker;
 
 import java.lang.annotation.Retention;
@@ -46,51 +53,49 @@
     /**
      * Transmission Mode undefined.
      */
-    public static final int TRANSMISSION_MODE_UNDEFINED =
-            Constants.FrontendDvbtTransmissionMode.UNDEFINED;
+    public static final int TRANSMISSION_MODE_UNDEFINED = FrontendDvbtTransmissionMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Transmission Mode automatically
      */
-    public static final int TRANSMISSION_MODE_AUTO = Constants.FrontendDvbtTransmissionMode.AUTO;
+    public static final int TRANSMISSION_MODE_AUTO = FrontendDvbtTransmissionMode.AUTO;
     /**
      * 2K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_2K = Constants.FrontendDvbtTransmissionMode.MODE_2K;
+    public static final int TRANSMISSION_MODE_2K = FrontendDvbtTransmissionMode.MODE_2K;
     /**
      * 8K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_8K = Constants.FrontendDvbtTransmissionMode.MODE_8K;
+    public static final int TRANSMISSION_MODE_8K = FrontendDvbtTransmissionMode.MODE_8K;
     /**
      * 4K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_4K = Constants.FrontendDvbtTransmissionMode.MODE_4K;
+    public static final int TRANSMISSION_MODE_4K = FrontendDvbtTransmissionMode.MODE_4K;
     /**
      * 1K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_1K = Constants.FrontendDvbtTransmissionMode.MODE_1K;
+    public static final int TRANSMISSION_MODE_1K = FrontendDvbtTransmissionMode.MODE_1K;
     /**
      * 16K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_16K = Constants.FrontendDvbtTransmissionMode.MODE_16K;
+    public static final int TRANSMISSION_MODE_16K = FrontendDvbtTransmissionMode.MODE_16K;
     /**
      * 32K Transmission Mode.
      */
-    public static final int TRANSMISSION_MODE_32K = Constants.FrontendDvbtTransmissionMode.MODE_32K;
+    public static final int TRANSMISSION_MODE_32K = FrontendDvbtTransmissionMode.MODE_32K;
     /**
      * 8K Transmission Extended Mode.
      */
-    public static final int TRANSMISSION_MODE_EXTENDED_8K =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_8K_E;
+    public static final int TRANSMISSION_MODE_EXTENDED_8K = FrontendDvbtTransmissionMode.MODE_8K_E;
     /**
      * 16K Transmission Extended Mode.
      */
     public static final int TRANSMISSION_MODE_EXTENDED_16K =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_16K_E;
+            FrontendDvbtTransmissionMode.MODE_16K_E;
     /**
      * 32K Transmission Extended Mode.
      */
     public static final int TRANSMISSION_MODE_EXTENDED_32K =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_32K_E;
+            FrontendDvbtTransmissionMode.MODE_32K_E;
 
     /** @hide */
     @IntDef(flag = true,
@@ -103,35 +108,35 @@
     /**
      * Bandwidth undefined.
      */
-    public static final int BANDWIDTH_UNDEFINED = Constants.FrontendDvbtBandwidth.UNDEFINED;
+    public static final int BANDWIDTH_UNDEFINED = FrontendDvbtBandwidth.UNDEFINED;
     /**
      * Hardware is able to detect and set Bandwidth automatically.
      */
-    public static final int BANDWIDTH_AUTO = Constants.FrontendDvbtBandwidth.AUTO;
+    public static final int BANDWIDTH_AUTO = FrontendDvbtBandwidth.AUTO;
     /**
      * 8 MHz bandwidth.
      */
-    public static final int BANDWIDTH_8MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_8MHZ;
+    public static final int BANDWIDTH_8MHZ = FrontendDvbtBandwidth.BANDWIDTH_8MHZ;
     /**
      * 7 MHz bandwidth.
      */
-    public static final int BANDWIDTH_7MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_7MHZ;
+    public static final int BANDWIDTH_7MHZ = FrontendDvbtBandwidth.BANDWIDTH_7MHZ;
     /**
      * 6 MHz bandwidth.
      */
-    public static final int BANDWIDTH_6MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_6MHZ;
+    public static final int BANDWIDTH_6MHZ = FrontendDvbtBandwidth.BANDWIDTH_6MHZ;
     /**
      * 5 MHz bandwidth.
      */
-    public static final int BANDWIDTH_5MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_5MHZ;
+    public static final int BANDWIDTH_5MHZ = FrontendDvbtBandwidth.BANDWIDTH_5MHZ;
     /**
      * 1,7 MHz bandwidth.
      */
-    public static final int BANDWIDTH_1_7MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_1_7MHZ;
+    public static final int BANDWIDTH_1_7MHZ = FrontendDvbtBandwidth.BANDWIDTH_1_7MHZ;
     /**
      * 10 MHz bandwidth.
      */
-    public static final int BANDWIDTH_10MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_10MHZ;
+    public static final int BANDWIDTH_10MHZ = FrontendDvbtBandwidth.BANDWIDTH_10MHZ;
 
 
     /** @hide */
@@ -147,55 +152,44 @@
     /**
      * Constellation not defined.
      */
-    public static final int CONSTELLATION_UNDEFINED = Constants.FrontendDvbtConstellation.UNDEFINED;
+    public static final int CONSTELLATION_UNDEFINED = FrontendDvbtConstellation.UNDEFINED;
     /**
      * Hardware is able to detect and set Constellation automatically.
      */
-    public static final int CONSTELLATION_AUTO = Constants.FrontendDvbtConstellation.AUTO;
+    public static final int CONSTELLATION_AUTO = FrontendDvbtConstellation.AUTO;
     /**
      * QPSK Constellation.
      */
-    public static final int CONSTELLATION_QPSK =
-            Constants.FrontendDvbtConstellation.CONSTELLATION_QPSK;
+    public static final int CONSTELLATION_QPSK = FrontendDvbtConstellation.CONSTELLATION_QPSK;
     /**
      * 16QAM Constellation.
      */
-    public static final int CONSTELLATION_16QAM =
-            Constants.FrontendDvbtConstellation.CONSTELLATION_16QAM;
+    public static final int CONSTELLATION_16QAM = FrontendDvbtConstellation.CONSTELLATION_16QAM;
     /**
      * 64QAM Constellation.
      */
-    public static final int CONSTELLATION_64QAM =
-            Constants.FrontendDvbtConstellation.CONSTELLATION_64QAM;
+    public static final int CONSTELLATION_64QAM = FrontendDvbtConstellation.CONSTELLATION_64QAM;
     /**
      * 256QAM Constellation.
      */
-    public static final int CONSTELLATION_256QAM =
-            Constants.FrontendDvbtConstellation.CONSTELLATION_256QAM;
+    public static final int CONSTELLATION_256QAM = FrontendDvbtConstellation.CONSTELLATION_256QAM;
     /**
      * QPSK Rotated Constellation.
      */
-    public static final int CONSTELLATION_QPSK_R =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
-                    .CONSTELLATION_QPSK_R;
+    public static final int CONSTELLATION_QPSK_R = FrontendDvbtConstellation.CONSTELLATION_QPSK_R;
     /**
      * 16QAM Rotated Constellation.
      */
-    public static final int CONSTELLATION_16QAM_R =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
-                    .CONSTELLATION_16QAM_R;
+    public static final int CONSTELLATION_16QAM_R = FrontendDvbtConstellation.CONSTELLATION_16QAM_R;
     /**
      * 64QAM Rotated Constellation.
      */
-    public static final int CONSTELLATION_64QAM_R =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
-                    .CONSTELLATION_64QAM_R;
+    public static final int CONSTELLATION_64QAM_R = FrontendDvbtConstellation.CONSTELLATION_64QAM_R;
     /**
      * 256QAM Rotated Constellation.
      */
     public static final int CONSTELLATION_256QAM_R =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
-                    .CONSTELLATION_256QAM_R;
+            FrontendDvbtConstellation.CONSTELLATION_256QAM_R;
 
     /** @hide */
     @IntDef(flag = true,
@@ -209,48 +203,43 @@
     /**
      * Hierarchy undefined.
      */
-    public static final int HIERARCHY_UNDEFINED = Constants.FrontendDvbtHierarchy.UNDEFINED;
+    public static final int HIERARCHY_UNDEFINED = FrontendDvbtHierarchy.UNDEFINED;
     /**
      * Hardware is able to detect and set Hierarchy automatically.
      */
-    public static final int HIERARCHY_AUTO = Constants.FrontendDvbtHierarchy.AUTO;
+    public static final int HIERARCHY_AUTO = FrontendDvbtHierarchy.AUTO;
     /**
      * Non-native Hierarchy
      */
-    public static final int HIERARCHY_NON_NATIVE =
-            Constants.FrontendDvbtHierarchy.HIERARCHY_NON_NATIVE;
+    public static final int HIERARCHY_NON_NATIVE = FrontendDvbtHierarchy.HIERARCHY_NON_NATIVE;
     /**
      * 1-native Hierarchy
      */
-    public static final int HIERARCHY_1_NATIVE = Constants.FrontendDvbtHierarchy.HIERARCHY_1_NATIVE;
+    public static final int HIERARCHY_1_NATIVE = FrontendDvbtHierarchy.HIERARCHY_1_NATIVE;
     /**
      * 2-native Hierarchy
      */
-    public static final int HIERARCHY_2_NATIVE = Constants.FrontendDvbtHierarchy.HIERARCHY_2_NATIVE;
+    public static final int HIERARCHY_2_NATIVE = FrontendDvbtHierarchy.HIERARCHY_2_NATIVE;
     /**
      * 4-native Hierarchy
      */
-    public static final int HIERARCHY_4_NATIVE = Constants.FrontendDvbtHierarchy.HIERARCHY_4_NATIVE;
+    public static final int HIERARCHY_4_NATIVE = FrontendDvbtHierarchy.HIERARCHY_4_NATIVE;
     /**
      * Non-indepth Hierarchy
      */
-    public static final int HIERARCHY_NON_INDEPTH =
-            Constants.FrontendDvbtHierarchy.HIERARCHY_NON_INDEPTH;
+    public static final int HIERARCHY_NON_INDEPTH = FrontendDvbtHierarchy.HIERARCHY_NON_INDEPTH;
     /**
      * 1-indepth Hierarchy
      */
-    public static final int HIERARCHY_1_INDEPTH =
-            Constants.FrontendDvbtHierarchy.HIERARCHY_1_INDEPTH;
+    public static final int HIERARCHY_1_INDEPTH = FrontendDvbtHierarchy.HIERARCHY_1_INDEPTH;
     /**
      * 2-indepth Hierarchy
      */
-    public static final int HIERARCHY_2_INDEPTH =
-            Constants.FrontendDvbtHierarchy.HIERARCHY_2_INDEPTH;
+    public static final int HIERARCHY_2_INDEPTH = FrontendDvbtHierarchy.HIERARCHY_2_INDEPTH;
     /**
      * 4-indepth Hierarchy
      */
-    public static final int HIERARCHY_4_INDEPTH =
-            Constants.FrontendDvbtHierarchy.HIERARCHY_4_INDEPTH;
+    public static final int HIERARCHY_4_INDEPTH = FrontendDvbtHierarchy.HIERARCHY_4_INDEPTH;
 
 
     /** @hide */
@@ -264,48 +253,47 @@
     /**
      * Code rate undefined.
      */
-    public static final int CODERATE_UNDEFINED =
-            Constants.FrontendDvbtCoderate.UNDEFINED;
+    public static final int CODERATE_UNDEFINED = FrontendDvbtCoderate.UNDEFINED;
     /**
      * Hardware is able to detect and set code rate automatically.
      */
-    public static final int CODERATE_AUTO = Constants.FrontendDvbtCoderate.AUTO;
+    public static final int CODERATE_AUTO = FrontendDvbtCoderate.AUTO;
     /**
      * 1/2 code rate.
      */
-    public static final int CODERATE_1_2 = Constants.FrontendDvbtCoderate.CODERATE_1_2;
+    public static final int CODERATE_1_2 = FrontendDvbtCoderate.CODERATE_1_2;
     /**
      * 2/3 code rate.
      */
-    public static final int CODERATE_2_3 = Constants.FrontendDvbtCoderate.CODERATE_2_3;
+    public static final int CODERATE_2_3 = FrontendDvbtCoderate.CODERATE_2_3;
     /**
      * 3/4 code rate.
      */
-    public static final int CODERATE_3_4 = Constants.FrontendDvbtCoderate.CODERATE_3_4;
+    public static final int CODERATE_3_4 = FrontendDvbtCoderate.CODERATE_3_4;
     /**
      * 5/6 code rate.
      */
-    public static final int CODERATE_5_6 = Constants.FrontendDvbtCoderate.CODERATE_5_6;
+    public static final int CODERATE_5_6 = FrontendDvbtCoderate.CODERATE_5_6;
     /**
      * 7/8 code rate.
      */
-    public static final int CODERATE_7_8 = Constants.FrontendDvbtCoderate.CODERATE_7_8;
+    public static final int CODERATE_7_8 = FrontendDvbtCoderate.CODERATE_7_8;
     /**
      * 4/5 code rate.
      */
-    public static final int CODERATE_3_5 = Constants.FrontendDvbtCoderate.CODERATE_3_5;
+    public static final int CODERATE_3_5 = FrontendDvbtCoderate.CODERATE_3_5;
     /**
      * 4/5 code rate.
      */
-    public static final int CODERATE_4_5 = Constants.FrontendDvbtCoderate.CODERATE_4_5;
+    public static final int CODERATE_4_5 = FrontendDvbtCoderate.CODERATE_4_5;
     /**
      * 6/7 code rate.
      */
-    public static final int CODERATE_6_7 = Constants.FrontendDvbtCoderate.CODERATE_6_7;
+    public static final int CODERATE_6_7 = FrontendDvbtCoderate.CODERATE_6_7;
     /**
      * 8/9 code rate.
      */
-    public static final int CODERATE_8_9 = Constants.FrontendDvbtCoderate.CODERATE_8_9;
+    public static final int CODERATE_8_9 = FrontendDvbtCoderate.CODERATE_8_9;
 
     /** @hide */
     @IntDef(flag = true,
@@ -323,46 +311,39 @@
      * Guard Interval undefined.
      */
     public static final int GUARD_INTERVAL_UNDEFINED =
-            Constants.FrontendDvbtGuardInterval.UNDEFINED;
+            FrontendDvbtGuardInterval.UNDEFINED;
     /**
      * Hardware is able to detect and set Guard Interval automatically.
      */
-    public static final int GUARD_INTERVAL_AUTO = Constants.FrontendDvbtGuardInterval.AUTO;
+    public static final int GUARD_INTERVAL_AUTO = FrontendDvbtGuardInterval.AUTO;
     /**
      * 1/32 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_1_32 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_1_32;
+    public static final int GUARD_INTERVAL_1_32 = FrontendDvbtGuardInterval.INTERVAL_1_32;
     /**
      * 1/16 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_1_16 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_1_16;
+    public static final int GUARD_INTERVAL_1_16 = FrontendDvbtGuardInterval.INTERVAL_1_16;
     /**
      * 1/8 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_1_8 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_1_8;
+    public static final int GUARD_INTERVAL_1_8 = FrontendDvbtGuardInterval.INTERVAL_1_8;
     /**
      * 1/4 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_1_4 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_1_4;
+    public static final int GUARD_INTERVAL_1_4 = FrontendDvbtGuardInterval.INTERVAL_1_4;
     /**
      * 1/128 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_1_128 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_1_128;
+    public static final int GUARD_INTERVAL_1_128 = FrontendDvbtGuardInterval.INTERVAL_1_128;
     /**
      * 19/128 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_19_128 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_19_128;
+    public static final int GUARD_INTERVAL_19_128 = FrontendDvbtGuardInterval.INTERVAL_19_128;
     /**
      * 19/256 Guard Interval.
      */
-    public static final int GUARD_INTERVAL_19_256 =
-            Constants.FrontendDvbtGuardInterval.INTERVAL_19_256;
+    public static final int GUARD_INTERVAL_19_256 = FrontendDvbtGuardInterval.INTERVAL_19_256;
 
     /** @hide */
     @IntDef(flag = true,
@@ -375,15 +356,15 @@
     /**
      * Hardware is able to detect and set Standard automatically.
      */
-    public static final int STANDARD_AUTO = Constants.FrontendDvbtStandard.AUTO;
+    public static final int STANDARD_AUTO = FrontendDvbtStandard.AUTO;
     /**
      * T standard.
      */
-    public static final int STANDARD_T = Constants.FrontendDvbtStandard.T;
+    public static final int STANDARD_T = FrontendDvbtStandard.T;
     /**
      * T2 standard.
      */
-    public static final int STANDARD_T2 = Constants.FrontendDvbtStandard.T2;
+    public static final int STANDARD_T2 = FrontendDvbtStandard.T2;
 
     /** @hide */
     @IntDef(prefix = "PLP_MODE_",
@@ -394,15 +375,15 @@
     /**
      * Physical Layer Pipe (PLP) Mode undefined.
      */
-    public static final int PLP_MODE_UNDEFINED = Constants.FrontendDvbtPlpMode.UNDEFINED;
+    public static final int PLP_MODE_UNDEFINED = FrontendDvbtPlpMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Physical Layer Pipe (PLP) Mode automatically.
      */
-    public static final int PLP_MODE_AUTO = Constants.FrontendDvbtPlpMode.AUTO;
+    public static final int PLP_MODE_AUTO = FrontendDvbtPlpMode.AUTO;
     /**
      * Physical Layer Pipe (PLP) manual Mode.
      */
-    public static final int PLP_MODE_MANUAL = Constants.FrontendDvbtPlpMode.MANUAL;
+    public static final int PLP_MODE_MANUAL = FrontendDvbtPlpMode.MANUAL;
 
     private int mTransmissionMode;
     private final int mBandwidth;
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 4bfe807..4a31686 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -20,7 +20,8 @@
 import android.annotation.IntRange;
 import android.annotation.LongDef;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendInnerFec;
+import android.hardware.tv.tuner.FrontendType;
 import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerVersionChecker;
 
@@ -44,47 +45,47 @@
     /**
      * Undefined frontend type.
      */
-    public static final int TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED;
+    public static final int TYPE_UNDEFINED = FrontendType.UNDEFINED;
     /**
      * Analog frontend type.
      */
-    public static final int TYPE_ANALOG = Constants.FrontendType.ANALOG;
+    public static final int TYPE_ANALOG = FrontendType.ANALOG;
     /**
      * Advanced Television Systems Committee (ATSC) frontend type.
      */
-    public static final int TYPE_ATSC = Constants.FrontendType.ATSC;
+    public static final int TYPE_ATSC = FrontendType.ATSC;
     /**
      * Advanced Television Systems Committee 3.0 (ATSC-3) frontend type.
      */
-    public static final int TYPE_ATSC3 = Constants.FrontendType.ATSC3;
+    public static final int TYPE_ATSC3 = FrontendType.ATSC3;
     /**
      * Digital Video Broadcasting-Cable (DVB-C) frontend type.
      */
-    public static final int TYPE_DVBC = Constants.FrontendType.DVBC;
+    public static final int TYPE_DVBC = FrontendType.DVBC;
     /**
      * Digital Video Broadcasting-Satellite (DVB-S) frontend type.
      */
-    public static final int TYPE_DVBS = Constants.FrontendType.DVBS;
+    public static final int TYPE_DVBS = FrontendType.DVBS;
     /**
      * Digital Video Broadcasting-Terrestrial (DVB-T) frontend type.
      */
-    public static final int TYPE_DVBT = Constants.FrontendType.DVBT;
+    public static final int TYPE_DVBT = FrontendType.DVBT;
     /**
      * Integrated Services Digital Broadcasting-Satellite (ISDB-S) frontend type.
      */
-    public static final int TYPE_ISDBS = Constants.FrontendType.ISDBS;
+    public static final int TYPE_ISDBS = FrontendType.ISDBS;
     /**
      * Integrated Services Digital Broadcasting-Satellite 3 (ISDB-S3) frontend type.
      */
-    public static final int TYPE_ISDBS3 = Constants.FrontendType.ISDBS3;
+    public static final int TYPE_ISDBS3 = FrontendType.ISDBS3;
     /**
      * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T) frontend type.
      */
-    public static final int TYPE_ISDBT = Constants.FrontendType.ISDBT;
+    public static final int TYPE_ISDBT = FrontendType.ISDBT;
     /**
      * Digital Terrestrial Multimedia Broadcast standard (DTMB) frontend type.
      */
-    public static final int TYPE_DTMB = android.hardware.tv.tuner.V1_1.Constants.FrontendType.DTMB;
+    public static final int TYPE_DTMB = FrontendType.DTMB;
 
 
     /** @hide */
@@ -101,151 +102,151 @@
     /**
      * FEC not defined.
      */
-    public static final long FEC_UNDEFINED = Constants.FrontendInnerFec.FEC_UNDEFINED;
+    public static final long FEC_UNDEFINED = FrontendInnerFec.FEC_UNDEFINED;
     /**
      * hardware is able to detect and set FEC automatically.
      */
-    public static final long FEC_AUTO = Constants.FrontendInnerFec.AUTO;
+    public static final long FEC_AUTO = FrontendInnerFec.AUTO;
     /**
      * 1/2 conv. code rate.
      */
-    public static final long FEC_1_2 = Constants.FrontendInnerFec.FEC_1_2;
+    public static final long FEC_1_2 = FrontendInnerFec.FEC_1_2;
     /**
      * 1/3 conv. code rate.
      */
-    public static final long FEC_1_3 = Constants.FrontendInnerFec.FEC_1_3;
+    public static final long FEC_1_3 = FrontendInnerFec.FEC_1_3;
     /**
      * 1/4 conv. code rate.
      */
-    public static final long FEC_1_4 = Constants.FrontendInnerFec.FEC_1_4;
+    public static final long FEC_1_4 = FrontendInnerFec.FEC_1_4;
     /**
      * 1/5 conv. code rate.
      */
-    public static final long FEC_1_5 = Constants.FrontendInnerFec.FEC_1_5;
+    public static final long FEC_1_5 = FrontendInnerFec.FEC_1_5;
     /**
      * 2/3 conv. code rate.
      */
-    public static final long FEC_2_3 = Constants.FrontendInnerFec.FEC_2_3;
+    public static final long FEC_2_3 = FrontendInnerFec.FEC_2_3;
     /**
      * 2/5 conv. code rate.
      */
-    public static final long FEC_2_5 = Constants.FrontendInnerFec.FEC_2_5;
+    public static final long FEC_2_5 = FrontendInnerFec.FEC_2_5;
     /**
      * 2/9 conv. code rate.
      */
-    public static final long FEC_2_9 = Constants.FrontendInnerFec.FEC_2_9;
+    public static final long FEC_2_9 = FrontendInnerFec.FEC_2_9;
     /**
      * 3/4 conv. code rate.
      */
-    public static final long FEC_3_4 = Constants.FrontendInnerFec.FEC_3_4;
+    public static final long FEC_3_4 = FrontendInnerFec.FEC_3_4;
     /**
      * 3/5 conv. code rate.
      */
-    public static final long FEC_3_5 = Constants.FrontendInnerFec.FEC_3_5;
+    public static final long FEC_3_5 = FrontendInnerFec.FEC_3_5;
     /**
      * 4/5 conv. code rate.
      */
-    public static final long FEC_4_5 = Constants.FrontendInnerFec.FEC_4_5;
+    public static final long FEC_4_5 = FrontendInnerFec.FEC_4_5;
     /**
      * 4/15 conv. code rate.
      */
-    public static final long FEC_4_15 = Constants.FrontendInnerFec.FEC_4_15;
+    public static final long FEC_4_15 = FrontendInnerFec.FEC_4_15;
     /**
      * 5/6 conv. code rate.
      */
-    public static final long FEC_5_6 = Constants.FrontendInnerFec.FEC_5_6;
+    public static final long FEC_5_6 = FrontendInnerFec.FEC_5_6;
     /**
      * 5/9 conv. code rate.
      */
-    public static final long FEC_5_9 = Constants.FrontendInnerFec.FEC_5_9;
+    public static final long FEC_5_9 = FrontendInnerFec.FEC_5_9;
     /**
      * 6/7 conv. code rate.
      */
-    public static final long FEC_6_7 = Constants.FrontendInnerFec.FEC_6_7;
+    public static final long FEC_6_7 = FrontendInnerFec.FEC_6_7;
     /**
      * 7/8 conv. code rate.
      */
-    public static final long FEC_7_8 = Constants.FrontendInnerFec.FEC_7_8;
+    public static final long FEC_7_8 = FrontendInnerFec.FEC_7_8;
     /**
      * 7/9 conv. code rate.
      */
-    public static final long FEC_7_9 = Constants.FrontendInnerFec.FEC_7_9;
+    public static final long FEC_7_9 = FrontendInnerFec.FEC_7_9;
     /**
      * 7/15 conv. code rate.
      */
-    public static final long FEC_7_15 = Constants.FrontendInnerFec.FEC_7_15;
+    public static final long FEC_7_15 = FrontendInnerFec.FEC_7_15;
     /**
      * 8/9 conv. code rate.
      */
-    public static final long FEC_8_9 = Constants.FrontendInnerFec.FEC_8_9;
+    public static final long FEC_8_9 = FrontendInnerFec.FEC_8_9;
     /**
      * 8/15 conv. code rate.
      */
-    public static final long FEC_8_15 = Constants.FrontendInnerFec.FEC_8_15;
+    public static final long FEC_8_15 = FrontendInnerFec.FEC_8_15;
     /**
      * 9/10 conv. code rate.
      */
-    public static final long FEC_9_10 = Constants.FrontendInnerFec.FEC_9_10;
+    public static final long FEC_9_10 = FrontendInnerFec.FEC_9_10;
     /**
      * 9/20 conv. code rate.
      */
-    public static final long FEC_9_20 = Constants.FrontendInnerFec.FEC_9_20;
+    public static final long FEC_9_20 = FrontendInnerFec.FEC_9_20;
     /**
      * 11/15 conv. code rate.
      */
-    public static final long FEC_11_15 = Constants.FrontendInnerFec.FEC_11_15;
+    public static final long FEC_11_15 = FrontendInnerFec.FEC_11_15;
     /**
      * 11/20 conv. code rate.
      */
-    public static final long FEC_11_20 = Constants.FrontendInnerFec.FEC_11_20;
+    public static final long FEC_11_20 = FrontendInnerFec.FEC_11_20;
     /**
      * 11/45 conv. code rate.
      */
-    public static final long FEC_11_45 = Constants.FrontendInnerFec.FEC_11_45;
+    public static final long FEC_11_45 = FrontendInnerFec.FEC_11_45;
     /**
      * 13/18 conv. code rate.
      */
-    public static final long FEC_13_18 = Constants.FrontendInnerFec.FEC_13_18;
+    public static final long FEC_13_18 = FrontendInnerFec.FEC_13_18;
     /**
      * 13/45 conv. code rate.
      */
-    public static final long FEC_13_45 = Constants.FrontendInnerFec.FEC_13_45;
+    public static final long FEC_13_45 = FrontendInnerFec.FEC_13_45;
     /**
      * 14/45 conv. code rate.
      */
-    public static final long FEC_14_45 = Constants.FrontendInnerFec.FEC_14_45;
+    public static final long FEC_14_45 = FrontendInnerFec.FEC_14_45;
     /**
      * 23/36 conv. code rate.
      */
-    public static final long FEC_23_36 = Constants.FrontendInnerFec.FEC_23_36;
+    public static final long FEC_23_36 = FrontendInnerFec.FEC_23_36;
     /**
      * 25/36 conv. code rate.
      */
-    public static final long FEC_25_36 = Constants.FrontendInnerFec.FEC_25_36;
+    public static final long FEC_25_36 = FrontendInnerFec.FEC_25_36;
     /**
      * 26/45 conv. code rate.
      */
-    public static final long FEC_26_45 = Constants.FrontendInnerFec.FEC_26_45;
+    public static final long FEC_26_45 = FrontendInnerFec.FEC_26_45;
     /**
      * 28/45 conv. code rate.
      */
-    public static final long FEC_28_45 = Constants.FrontendInnerFec.FEC_28_45;
+    public static final long FEC_28_45 = FrontendInnerFec.FEC_28_45;
     /**
      * 29/45 conv. code rate.
      */
-    public static final long FEC_29_45 = Constants.FrontendInnerFec.FEC_29_45;
+    public static final long FEC_29_45 = FrontendInnerFec.FEC_29_45;
     /**
      * 31/45 conv. code rate.
      */
-    public static final long FEC_31_45 = Constants.FrontendInnerFec.FEC_31_45;
+    public static final long FEC_31_45 = FrontendInnerFec.FEC_31_45;
     /**
      * 32/45 conv. code rate.
      */
-    public static final long FEC_32_45 = Constants.FrontendInnerFec.FEC_32_45;
+    public static final long FEC_32_45 = FrontendInnerFec.FEC_32_45;
     /**
      * 77/90 conv. code rate.
      */
-    public static final long FEC_77_90 = Constants.FrontendInnerFec.FEC_77_90;
+    public static final long FEC_77_90 = FrontendInnerFec.FEC_77_90;
 
     /** @hide */
     @IntDef(prefix = "FRONTEND_SPECTRAL_INVERSION_",
@@ -258,17 +259,17 @@
      * Spectral Inversion Type undefined.
      */
     public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED =
-            Constants.FrontendDvbcSpectralInversion.UNDEFINED;
+            android.hardware.tv.tuner.FrontendSpectralInversion.UNDEFINED;
     /**
      * Normal Spectral Inversion.
      */
     public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL =
-            Constants.FrontendDvbcSpectralInversion.NORMAL;
+            android.hardware.tv.tuner.FrontendSpectralInversion.NORMAL;
     /**
      * Inverted Spectral Inversion.
      */
     public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED =
-            Constants.FrontendDvbcSpectralInversion.INVERTED;
+            android.hardware.tv.tuner.FrontendSpectralInversion.INVERTED;
 
 
 
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index b82a5a9..36fd942 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -20,7 +20,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
 import android.media.tv.tuner.Lnb;
 import android.media.tv.tuner.TunerVersionChecker;
 
@@ -61,175 +60,188 @@
      * Lock status for Demod.
      */
     public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK =
-            Constants.FrontendStatusType.DEMOD_LOCK;
+            android.hardware.tv.tuner.FrontendStatusType.DEMOD_LOCK;
     /**
      * Signal to Noise Ratio.
      */
-    public static final int FRONTEND_STATUS_TYPE_SNR = Constants.FrontendStatusType.SNR;
+    public static final int FRONTEND_STATUS_TYPE_SNR =
+            android.hardware.tv.tuner.FrontendStatusType.SNR;
     /**
      * Bit Error Ratio.
      */
-    public static final int FRONTEND_STATUS_TYPE_BER = Constants.FrontendStatusType.BER;
+    public static final int FRONTEND_STATUS_TYPE_BER =
+            android.hardware.tv.tuner.FrontendStatusType.BER;
     /**
      * Packages Error Ratio.
      */
-    public static final int FRONTEND_STATUS_TYPE_PER = Constants.FrontendStatusType.PER;
+    public static final int FRONTEND_STATUS_TYPE_PER =
+            android.hardware.tv.tuner.FrontendStatusType.PER;
     /**
      * Bit Error Ratio before FEC.
      */
-    public static final int FRONTEND_STATUS_TYPE_PRE_BER = Constants.FrontendStatusType.PRE_BER;
+    public static final int FRONTEND_STATUS_TYPE_PRE_BER =
+            android.hardware.tv.tuner.FrontendStatusType.PRE_BER;
     /**
      * Signal Quality (0..100). Good data over total data in percent can be
      * used as a way to present Signal Quality.
      */
     public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY =
-            Constants.FrontendStatusType.SIGNAL_QUALITY;
+            android.hardware.tv.tuner.FrontendStatusType.SIGNAL_QUALITY;
     /**
      * Signal Strength.
      */
     public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH =
-            Constants.FrontendStatusType.SIGNAL_STRENGTH;
+            android.hardware.tv.tuner.FrontendStatusType.SIGNAL_STRENGTH;
     /**
      * Symbol Rate in symbols per second.
      */
     public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE =
-            Constants.FrontendStatusType.SYMBOL_RATE;
+            android.hardware.tv.tuner.FrontendStatusType.SYMBOL_RATE;
     /**
      * Forward Error Correction Type.
      */
-    public static final int FRONTEND_STATUS_TYPE_FEC = Constants.FrontendStatusType.FEC;
+    public static final int FRONTEND_STATUS_TYPE_FEC =
+            android.hardware.tv.tuner.FrontendStatusType.FEC;
     /**
      * Modulation Type.
      */
     public static final int FRONTEND_STATUS_TYPE_MODULATION =
-            Constants.FrontendStatusType.MODULATION;
+            android.hardware.tv.tuner.FrontendStatusType.MODULATION;
     /**
      * Spectral Inversion Type.
      */
-    public static final int FRONTEND_STATUS_TYPE_SPECTRAL = Constants.FrontendStatusType.SPECTRAL;
+    public static final int FRONTEND_STATUS_TYPE_SPECTRAL =
+            android.hardware.tv.tuner.FrontendStatusType.SPECTRAL;
     /**
      * LNB Voltage.
      */
     public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE =
-            Constants.FrontendStatusType.LNB_VOLTAGE;
+            android.hardware.tv.tuner.FrontendStatusType.LNB_VOLTAGE;
     /**
      * Physical Layer Pipe ID.
      */
-    public static final int FRONTEND_STATUS_TYPE_PLP_ID = Constants.FrontendStatusType.PLP_ID;
+    public static final int FRONTEND_STATUS_TYPE_PLP_ID =
+            android.hardware.tv.tuner.FrontendStatusType.PLP_ID;
     /**
      * Status for Emergency Warning Broadcasting System.
      */
-    public static final int FRONTEND_STATUS_TYPE_EWBS = Constants.FrontendStatusType.EWBS;
+    public static final int FRONTEND_STATUS_TYPE_EWBS =
+            android.hardware.tv.tuner.FrontendStatusType.EWBS;
     /**
      * Automatic Gain Control.
      */
-    public static final int FRONTEND_STATUS_TYPE_AGC = Constants.FrontendStatusType.AGC;
+    public static final int FRONTEND_STATUS_TYPE_AGC =
+            android.hardware.tv.tuner.FrontendStatusType.AGC;
     /**
      * Low Noise Amplifier.
      */
-    public static final int FRONTEND_STATUS_TYPE_LNA = Constants.FrontendStatusType.LNA;
+    public static final int FRONTEND_STATUS_TYPE_LNA =
+            android.hardware.tv.tuner.FrontendStatusType.LNA;
     /**
      * Error status by layer.
      */
     public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR =
-            Constants.FrontendStatusType.LAYER_ERROR;
+            android.hardware.tv.tuner.FrontendStatusType.LAYER_ERROR;
     /**
      * Modulation Error Ratio.
      */
-    public static final int FRONTEND_STATUS_TYPE_MER = Constants.FrontendStatusType.MER;
+    public static final int FRONTEND_STATUS_TYPE_MER =
+            android.hardware.tv.tuner.FrontendStatusType.MER;
     /**
      * Difference between tuning frequency and actual locked frequency.
      */
     public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET =
-            Constants.FrontendStatusType.FREQ_OFFSET;
+            android.hardware.tv.tuner.FrontendStatusType.FREQ_OFFSET;
     /**
      * Hierarchy for DVBT.
      */
-    public static final int FRONTEND_STATUS_TYPE_HIERARCHY = Constants.FrontendStatusType.HIERARCHY;
+    public static final int FRONTEND_STATUS_TYPE_HIERARCHY =
+            android.hardware.tv.tuner.FrontendStatusType.HIERARCHY;
     /**
      * Lock status for RF.
      */
-    public static final int FRONTEND_STATUS_TYPE_RF_LOCK = Constants.FrontendStatusType.RF_LOCK;
+    public static final int FRONTEND_STATUS_TYPE_RF_LOCK =
+            android.hardware.tv.tuner.FrontendStatusType.RF_LOCK;
     /**
      * PLP information in a frequency band for ATSC-3.0 frontend.
      */
     public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO =
-            Constants.FrontendStatusType.ATSC3_PLP_INFO;
+            android.hardware.tv.tuner.FrontendStatusType.ATSC3_PLP_INFO;
     /**
      * BERS Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_BERS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.BERS;
+            android.hardware.tv.tuner.FrontendStatusType.BERS;
     /**
      * Coderate Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_CODERATES =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.CODERATES;
+            android.hardware.tv.tuner.FrontendStatusType.CODERATES;
     /**
      * Bandwidth Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_BANDWIDTH =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.BANDWIDTH;
+            android.hardware.tv.tuner.FrontendStatusType.BANDWIDTH;
     /**
      * Guard Interval Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_GUARD_INTERVAL =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.GUARD_INTERVAL;
+            android.hardware.tv.tuner.FrontendStatusType.GUARD_INTERVAL;
     /**
      * Transmission Mode Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_TRANSMISSION_MODE =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.TRANSMISSION_MODE;
+            android.hardware.tv.tuner.FrontendStatusType.TRANSMISSION_MODE;
     /**
      * UEC Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_UEC =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.UEC;
+            android.hardware.tv.tuner.FrontendStatusType.UEC;
     /**
      * T2 System Id Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.T2_SYSTEM_ID;
+            android.hardware.tv.tuner.FrontendStatusType.T2_SYSTEM_ID;
     /**
      * Interleavings Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.INTERLEAVINGS;
+            android.hardware.tv.tuner.FrontendStatusType.INTERLEAVINGS;
     /**
      * ISDBT Segments Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.ISDBT_SEGMENTS;
+            android.hardware.tv.tuner.FrontendStatusType.ISDBT_SEGMENTS;
     /**
      * TS Data Rates Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_TS_DATA_RATES =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.TS_DATA_RATES;
+            android.hardware.tv.tuner.FrontendStatusType.TS_DATA_RATES;
     /**
      * Extended Modulations Type. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_MODULATIONS_EXT =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.MODULATIONS;
+            android.hardware.tv.tuner.FrontendStatusType.MODULATIONS;
     /**
      * Roll Off Type status of the frontend. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_ROLL_OFF =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.ROLL_OFF;
+            android.hardware.tv.tuner.FrontendStatusType.ROLL_OFF;
     /**
      * If the frontend currently supports MISO or not. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_IS_MISO_ENABLED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_MISO;
+            android.hardware.tv.tuner.FrontendStatusType.IS_MISO;
     /**
      * If the frontend code rate is linear or not. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_IS_LINEAR =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_LINEAR;
+            android.hardware.tv.tuner.FrontendStatusType.IS_LINEAR;
     /**
      * If short frames is enabled or not. Only supported in Tuner HAL 1.1 or higher.
      */
     public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED =
-            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_SHORT_FRAMES;
+            android.hardware.tv.tuner.FrontendStatusType.IS_SHORT_FRAMES;
 
     /** @hide */
     @IntDef(value = {
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index 02cdb96..14b0b02 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -20,7 +20,9 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendIsdbs3Coderate;
+import android.hardware.tv.tuner.FrontendIsdbs3Modulation;
+import android.hardware.tv.tuner.FrontendIsdbs3Rolloff;
 import android.media.tv.tuner.Tuner;
 
 import java.lang.annotation.Retention;
@@ -45,31 +47,31 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendIsdbs3Modulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendIsdbs3Modulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically.
      */
-    public static final int MODULATION_AUTO = Constants.FrontendIsdbs3Modulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendIsdbs3Modulation.AUTO;
     /**
      * BPSK Modulation.
      */
-    public static final int MODULATION_MOD_BPSK = Constants.FrontendIsdbs3Modulation.MOD_BPSK;
+    public static final int MODULATION_MOD_BPSK = FrontendIsdbs3Modulation.MOD_BPSK;
     /**
      * QPSK Modulation.
      */
-    public static final int MODULATION_MOD_QPSK = Constants.FrontendIsdbs3Modulation.MOD_QPSK;
+    public static final int MODULATION_MOD_QPSK = FrontendIsdbs3Modulation.MOD_QPSK;
     /**
      * 8PSK Modulation.
      */
-    public static final int MODULATION_MOD_8PSK = Constants.FrontendIsdbs3Modulation.MOD_8PSK;
+    public static final int MODULATION_MOD_8PSK = FrontendIsdbs3Modulation.MOD_8PSK;
     /**
      * 16APSK Modulation.
      */
-    public static final int MODULATION_MOD_16APSK = Constants.FrontendIsdbs3Modulation.MOD_16APSK;
+    public static final int MODULATION_MOD_16APSK = FrontendIsdbs3Modulation.MOD_16APSK;
     /**
      * 32APSK Modulation.
      */
-    public static final int MODULATION_MOD_32APSK = Constants.FrontendIsdbs3Modulation.MOD_32APSK;
+    public static final int MODULATION_MOD_32APSK = FrontendIsdbs3Modulation.MOD_32APSK;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -83,55 +85,55 @@
     /**
      * Code rate undefined.
      */
-    public static final int CODERATE_UNDEFINED = Constants.FrontendIsdbs3Coderate.UNDEFINED;
+    public static final int CODERATE_UNDEFINED = FrontendIsdbs3Coderate.UNDEFINED;
     /**
      * Hardware is able to detect and set code rate automatically.
      */
-    public static final int CODERATE_AUTO = Constants.FrontendIsdbs3Coderate.AUTO;
+    public static final int CODERATE_AUTO = FrontendIsdbs3Coderate.AUTO;
     /**
      * 1/3 code rate.
      */
-    public static final int CODERATE_1_3 = Constants.FrontendIsdbs3Coderate.CODERATE_1_3;
+    public static final int CODERATE_1_3 = FrontendIsdbs3Coderate.CODERATE_1_3;
     /**
      * 2/5 code rate.
      */
-    public static final int CODERATE_2_5 = Constants.FrontendIsdbs3Coderate.CODERATE_2_5;
+    public static final int CODERATE_2_5 = FrontendIsdbs3Coderate.CODERATE_2_5;
     /**
      * 1/2 code rate.
      */
-    public static final int CODERATE_1_2 = Constants.FrontendIsdbs3Coderate.CODERATE_1_2;
+    public static final int CODERATE_1_2 = FrontendIsdbs3Coderate.CODERATE_1_2;
     /**
      * 3/5 code rate.
      */
-    public static final int CODERATE_3_5 = Constants.FrontendIsdbs3Coderate.CODERATE_3_5;
+    public static final int CODERATE_3_5 = FrontendIsdbs3Coderate.CODERATE_3_5;
     /**
      * 2/3 code rate.
      */
-    public static final int CODERATE_2_3 = Constants.FrontendIsdbs3Coderate.CODERATE_2_3;
+    public static final int CODERATE_2_3 = FrontendIsdbs3Coderate.CODERATE_2_3;
     /**
      * 3/4 code rate.
      */
-    public static final int CODERATE_3_4 = Constants.FrontendIsdbs3Coderate.CODERATE_3_4;
+    public static final int CODERATE_3_4 = FrontendIsdbs3Coderate.CODERATE_3_4;
     /**
      * 7/9 code rate.
      */
-    public static final int CODERATE_7_9 = Constants.FrontendIsdbs3Coderate.CODERATE_7_9;
+    public static final int CODERATE_7_9 = FrontendIsdbs3Coderate.CODERATE_7_9;
     /**
      * 4/5 code rate.
      */
-    public static final int CODERATE_4_5 = Constants.FrontendIsdbs3Coderate.CODERATE_4_5;
+    public static final int CODERATE_4_5 = FrontendIsdbs3Coderate.CODERATE_4_5;
     /**
      * 5/6 code rate.
      */
-    public static final int CODERATE_5_6 = Constants.FrontendIsdbs3Coderate.CODERATE_5_6;
+    public static final int CODERATE_5_6 = FrontendIsdbs3Coderate.CODERATE_5_6;
     /**
      * 7/8 code rate.
      */
-    public static final int CODERATE_7_8 = Constants.FrontendIsdbs3Coderate.CODERATE_7_8;
+    public static final int CODERATE_7_8 = FrontendIsdbs3Coderate.CODERATE_7_8;
     /**
      * 9/10 code rate.
      */
-    public static final int CODERATE_9_10 = Constants.FrontendIsdbs3Coderate.CODERATE_9_10;
+    public static final int CODERATE_9_10 = FrontendIsdbs3Coderate.CODERATE_9_10;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -142,11 +144,11 @@
     /**
      * Rolloff type undefined.
      */
-    public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbs3Rolloff.UNDEFINED;
+    public static final int ROLLOFF_UNDEFINED = FrontendIsdbs3Rolloff.UNDEFINED;
     /**
      * 0,03 Rolloff.
      */
-    public static final int ROLLOFF_0_03 = Constants.FrontendIsdbs3Rolloff.ROLLOFF_0_03;
+    public static final int ROLLOFF_0_03 = FrontendIsdbs3Rolloff.ROLLOFF_0_03;
 
 
     private final int mStreamId;
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index 3cc1aab..aab6408 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -20,7 +20,10 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendIsdbsCoderate;
+import android.hardware.tv.tuner.FrontendIsdbsModulation;
+import android.hardware.tv.tuner.FrontendIsdbsRolloff;
+import android.hardware.tv.tuner.FrontendIsdbsStreamIdType;
 import android.media.tv.tuner.Tuner;
 
 import java.lang.annotation.Retention;
@@ -42,12 +45,12 @@
     /**
      * Uses stream ID.
      */
-    public static final int STREAM_ID_TYPE_ID = Constants.FrontendIsdbsStreamIdType.STREAM_ID;
+    public static final int STREAM_ID_TYPE_ID = FrontendIsdbsStreamIdType.STREAM_ID;
     /**
      * Uses relative number.
      */
     public static final int STREAM_ID_TYPE_RELATIVE_NUMBER =
-            Constants.FrontendIsdbsStreamIdType.RELATIVE_STREAM_NUMBER;
+            FrontendIsdbsStreamIdType.RELATIVE_STREAM_NUMBER;
 
 
     /** @hide */
@@ -61,23 +64,23 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendIsdbsModulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendIsdbsModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically
      */
-    public static final int MODULATION_AUTO = Constants.FrontendIsdbsModulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendIsdbsModulation.AUTO;
     /**
      * BPSK Modulation.
      */
-    public static final int MODULATION_MOD_BPSK = Constants.FrontendIsdbsModulation.MOD_BPSK;
+    public static final int MODULATION_MOD_BPSK = FrontendIsdbsModulation.MOD_BPSK;
     /**
      * QPSK Modulation.
      */
-    public static final int MODULATION_MOD_QPSK = Constants.FrontendIsdbsModulation.MOD_QPSK;
+    public static final int MODULATION_MOD_QPSK = FrontendIsdbsModulation.MOD_QPSK;
     /**
      * TC8PSK Modulation.
      */
-    public static final int MODULATION_MOD_TC8PSK = Constants.FrontendIsdbsModulation.MOD_TC8PSK;
+    public static final int MODULATION_MOD_TC8PSK = FrontendIsdbsModulation.MOD_TC8PSK;
 
 
     /** @hide */
@@ -91,31 +94,31 @@
     /**
      * Code rate undefined.
      */
-    public static final int CODERATE_UNDEFINED = Constants.FrontendIsdbsCoderate.UNDEFINED;
+    public static final int CODERATE_UNDEFINED = FrontendIsdbsCoderate.UNDEFINED;
     /**
      * Hardware is able to detect and set code rate automatically.
      */
-    public static final int CODERATE_AUTO = Constants.FrontendIsdbsCoderate.AUTO;
+    public static final int CODERATE_AUTO = FrontendIsdbsCoderate.AUTO;
     /**
      * 1/2 code rate.
      */
-    public static final int CODERATE_1_2 = Constants.FrontendIsdbsCoderate.CODERATE_1_2;
+    public static final int CODERATE_1_2 = FrontendIsdbsCoderate.CODERATE_1_2;
     /**
      * 2/3 code rate.
      */
-    public static final int CODERATE_2_3 = Constants.FrontendIsdbsCoderate.CODERATE_2_3;
+    public static final int CODERATE_2_3 = FrontendIsdbsCoderate.CODERATE_2_3;
     /**
      * 3/4 code rate.
      */
-    public static final int CODERATE_3_4 = Constants.FrontendIsdbsCoderate.CODERATE_3_4;
+    public static final int CODERATE_3_4 = FrontendIsdbsCoderate.CODERATE_3_4;
     /**
      * 5/6 code rate.
      */
-    public static final int CODERATE_5_6 = Constants.FrontendIsdbsCoderate.CODERATE_5_6;
+    public static final int CODERATE_5_6 = FrontendIsdbsCoderate.CODERATE_5_6;
     /**
      * 7/8 code rate.
      */
-    public static final int CODERATE_7_8 = Constants.FrontendIsdbsCoderate.CODERATE_7_8;
+    public static final int CODERATE_7_8 = FrontendIsdbsCoderate.CODERATE_7_8;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -126,11 +129,11 @@
     /**
      * Rolloff type undefined.
      */
-    public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbsRolloff.UNDEFINED;
+    public static final int ROLLOFF_UNDEFINED = FrontendIsdbsRolloff.UNDEFINED;
     /**
      * 0,35 rolloff.
      */
-    public static final int ROLLOFF_0_35 = Constants.FrontendIsdbsRolloff.ROLLOFF_0_35;
+    public static final int ROLLOFF_0_35 = FrontendIsdbsRolloff.ROLLOFF_0_35;
 
 
     private final int mStreamId;
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index 6a14d08..de2476a 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
@@ -20,7 +20,9 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendIsdbtBandwidth;
+import android.hardware.tv.tuner.FrontendIsdbtMode;
+import android.hardware.tv.tuner.FrontendIsdbtModulation;
 import android.media.tv.tuner.frontend.DvbtFrontendSettings.CodeRate;
 
 import java.lang.annotation.Retention;
@@ -44,27 +46,27 @@
     /**
      * Modulation undefined.
      */
-    public static final int MODULATION_UNDEFINED = Constants.FrontendIsdbtModulation.UNDEFINED;
+    public static final int MODULATION_UNDEFINED = FrontendIsdbtModulation.UNDEFINED;
     /**
      * Hardware is able to detect and set modulation automatically
      */
-    public static final int MODULATION_AUTO = Constants.FrontendIsdbtModulation.AUTO;
+    public static final int MODULATION_AUTO = FrontendIsdbtModulation.AUTO;
     /**
      * DQPSK Modulation.
      */
-    public static final int MODULATION_MOD_DQPSK = Constants.FrontendIsdbtModulation.MOD_DQPSK;
+    public static final int MODULATION_MOD_DQPSK = FrontendIsdbtModulation.MOD_DQPSK;
     /**
      * QPSK Modulation.
      */
-    public static final int MODULATION_MOD_QPSK = Constants.FrontendIsdbtModulation.MOD_QPSK;
+    public static final int MODULATION_MOD_QPSK = FrontendIsdbtModulation.MOD_QPSK;
     /**
      * 16QAM Modulation.
      */
-    public static final int MODULATION_MOD_16QAM = Constants.FrontendIsdbtModulation.MOD_16QAM;
+    public static final int MODULATION_MOD_16QAM = FrontendIsdbtModulation.MOD_16QAM;
     /**
      * 64QAM Modulation.
      */
-    public static final int MODULATION_MOD_64QAM = Constants.FrontendIsdbtModulation.MOD_64QAM;
+    public static final int MODULATION_MOD_64QAM = FrontendIsdbtModulation.MOD_64QAM;
 
 
     /** @hide */
@@ -77,23 +79,23 @@
     /**
      * Mode undefined.
      */
-    public static final int MODE_UNDEFINED = Constants.FrontendIsdbtMode.UNDEFINED;
+    public static final int MODE_UNDEFINED = FrontendIsdbtMode.UNDEFINED;
     /**
      * Hardware is able to detect and set Mode automatically.
      */
-    public static final int MODE_AUTO = Constants.FrontendIsdbtMode.AUTO;
+    public static final int MODE_AUTO = FrontendIsdbtMode.AUTO;
     /**
      * Mode 1
      */
-    public static final int MODE_1 = Constants.FrontendIsdbtMode.MODE_1;
+    public static final int MODE_1 = FrontendIsdbtMode.MODE_1;
     /**
      * Mode 2
      */
-    public static final int MODE_2 = Constants.FrontendIsdbtMode.MODE_2;
+    public static final int MODE_2 = FrontendIsdbtMode.MODE_2;
     /**
      * Mode 3
      */
-    public static final int MODE_3 = Constants.FrontendIsdbtMode.MODE_3;
+    public static final int MODE_3 = FrontendIsdbtMode.MODE_3;
 
 
     /** @hide */
@@ -107,23 +109,23 @@
     /**
      * Bandwidth undefined.
      */
-    public static final int BANDWIDTH_UNDEFINED = Constants.FrontendIsdbtBandwidth.UNDEFINED;
+    public static final int BANDWIDTH_UNDEFINED = FrontendIsdbtBandwidth.UNDEFINED;
     /**
      * Hardware is able to detect and set Bandwidth automatically.
      */
-    public static final int BANDWIDTH_AUTO = Constants.FrontendIsdbtBandwidth.AUTO;
+    public static final int BANDWIDTH_AUTO = FrontendIsdbtBandwidth.AUTO;
     /**
      * 8 MHz bandwidth.
      */
-    public static final int BANDWIDTH_8MHZ = Constants.FrontendIsdbtBandwidth.BANDWIDTH_8MHZ;
+    public static final int BANDWIDTH_8MHZ = FrontendIsdbtBandwidth.BANDWIDTH_8MHZ;
     /**
      * 7 MHz bandwidth.
      */
-    public static final int BANDWIDTH_7MHZ = Constants.FrontendIsdbtBandwidth.BANDWIDTH_7MHZ;
+    public static final int BANDWIDTH_7MHZ = FrontendIsdbtBandwidth.BANDWIDTH_7MHZ;
     /**
      * 6 MHz bandwidth.
      */
-    public static final int BANDWIDTH_6MHZ = Constants.FrontendIsdbtBandwidth.BANDWIDTH_6MHZ;
+    public static final int BANDWIDTH_6MHZ = FrontendIsdbtBandwidth.BANDWIDTH_6MHZ;
 
     private final int mModulation;
     private final int mBandwidth;
diff --git a/media/java/android/media/tv/tuner/frontend/OnTuneEventListener.java b/media/java/android/media/tv/tuner/frontend/OnTuneEventListener.java
index 5cf0d31..3b5419e 100644
--- a/media/java/android/media/tv/tuner/frontend/OnTuneEventListener.java
+++ b/media/java/android/media/tv/tuner/frontend/OnTuneEventListener.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.hardware.tv.tuner.V1_0.Constants;
+import android.hardware.tv.tuner.FrontendEventType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -37,11 +37,11 @@
     @interface TuneEvent {}
 
     /** The frontend has locked to the signal specified by the tune method. */
-    int SIGNAL_LOCKED = Constants.FrontendEventType.LOCKED;
+    int SIGNAL_LOCKED = FrontendEventType.LOCKED;
     /** The frontend is unable to lock to the signal specified by the tune method. */
-    int SIGNAL_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL;
+    int SIGNAL_NO_SIGNAL = FrontendEventType.NO_SIGNAL;
     /** The frontend has lost the lock to the signal specified by the tune method. */
-    int SIGNAL_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK;
+    int SIGNAL_LOST_LOCK = FrontendEventType.LOST_LOCK;
 
     /** Tune Event from the frontend */
     void onTuneEvent(@TuneEvent int tuneEvent);
diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp
index c904ca2..65e7e10 100644
--- a/media/java/android/media/tv/tunerresourcemanager/Android.bp
+++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp
@@ -24,7 +24,7 @@
             enabled: true,
         },
         cpp: {
-            enabled: true,
+            enabled: false,
         },
         ndk: {
             enabled: true,
@@ -33,5 +33,4 @@
     srcs: [
         ":framework-media-tv-tunerresourcemanager-sources-aidl",
     ],
-    imports: ["tv_tuner_frontend_info_aidl_interface"],
 }
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index e399fbd..6f7adbc 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -24,7 +24,6 @@
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.media.tv.tuner.TunerFrontendInfo;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 483d972..a1f6687 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -16,13 +16,13 @@
 
 package android.media.tv.tunerresourcemanager;
 
-import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
+import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
new file mode 100644
index 0000000..8981ce0
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+/**
+ * FrontendInfo interface that carries tuner frontend information.
+ *
+ * This is used to update the TunerResourceManager fronted resources.
+ * @hide
+ */
+parcelable TunerFrontendInfo {
+    /**
+     * Frontend Handle
+     */
+    int handle;
+
+    /**
+     * Frontend Type
+     */
+    int type;
+
+    /**
+     * Frontends are assigned with the same exclusiveGroupId if they can't
+     * function at same time. For instance, they share same hardware module.
+     */
+    int exclusiveGroupId;
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index bc73f6a..e817f2d 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -172,8 +172,7 @@
 
     shared_libs: [
         "android.hardware.graphics.bufferqueue@2.0",
-        "android.hardware.tv.tuner@1.0",
-        "android.hardware.tv.tuner@1.1",
+        "android.hardware.tv.tuner-V1-ndk",
         "libbinder_ndk",
         "libandroid_runtime",
         "libcutils",
@@ -183,8 +182,7 @@
         "libmedia",
         "libnativehelper",
         "libutils",
-        "tv_tuner_aidl_interface-ndk_platform",
-        "tv_tuner_resource_manager_aidl_interface-ndk_platform",
+        "tv_tuner_aidl_interface-ndk",
     ],
 
     static_libs: [
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 3cf9b03..d1c4b34 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -14,154 +14,280 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "TvTuner-JNI"
-#include <utils/Log.h>
 
-#include "android_media_MediaCodecLinearBlock.h"
 #include "android_media_tv_Tuner.h"
-#include "android_runtime/AndroidRuntime.h"
 
+#include <aidl/android/hardware/tv/tuner/AudioExtraMetaData.h>
+#include <aidl/android/hardware/tv/tuner/AudioStreamType.h>
+#include <aidl/android/hardware/tv/tuner/AvStreamType.h>
+#include <aidl/android/hardware/tv/tuner/Constant.h>
+#include <aidl/android/hardware/tv/tuner/Constant64Bit.h>
+#include <aidl/android/hardware/tv/tuner/DataFormat.h>
+#include <aidl/android/hardware/tv/tuner/DemuxAlpFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxAlpFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxAlpLengthType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxCapabilities.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterAvSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterDownloadEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterIpPayloadEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterMainType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterMediaEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterPesDataSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterPesEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterRecordSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSectionBits.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSectionEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSectionSettingsCondition.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSubType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterTemiEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterTsRecordEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxIpAddress.h>
+#include <aidl/android/hardware/tv/tuner/DemuxIpFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxIpFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxMmtpFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxMmtpFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
+#include <aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxScHevcIndex.h>
+#include <aidl/android/hardware/tv/tuner/DemuxScIndex.h>
+#include <aidl/android/hardware/tv/tuner/DemuxTlvFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxTlvFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxTsFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxTsFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxTsIndex.h>
+#include <aidl/android/hardware/tv/tuner/DvrSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAnalogAftFlag.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAnalogSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAnalogSifStandard.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAnalogType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3Bandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3CodeRate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3DemodOutputFormat.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3Fec.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3Modulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3PlpSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3Settings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtsc3TimeInterleaveMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtscModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendAtscSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendBandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendCableTimeInterleaveMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbBandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbCapabilities.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbCodeRate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbGuardInterval.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbTimeInterleaveMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDtmbTransmissionMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbcAnnex.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbcBandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbcModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbcOuterFec.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbcSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsCodeRate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsPilot.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsRolloff.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsScanType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsStandard.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbsVcmMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtBandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtCoderate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtConstellation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtGuardInterval.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtHierarchy.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtPlpMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtStandard.h>
+#include <aidl/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendGuardInterval.h>
+#include <aidl/android/hardware/tv/tuner/FrontendInnerFec.h>
+#include <aidl/android/hardware/tv/tuner/FrontendInterleaveMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbs3Coderate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbs3Modulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbs3Rolloff.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbs3Settings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbsCoderate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbsModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbsRolloff.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbsSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbsStreamIdType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtBandwidth.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtCoderate.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtGuardInterval.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendIsdbtSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendModulation.h>
+#include <aidl/android/hardware/tv/tuner/FrontendModulationStatus.h>
+#include <aidl/android/hardware/tv/tuner/FrontendRollOff.h>
+#include <aidl/android/hardware/tv/tuner/FrontendScanAtsc3PlpInfo.h>
+#include <aidl/android/hardware/tv/tuner/FrontendScanMessageStandard.h>
+#include <aidl/android/hardware/tv/tuner/FrontendSpectralInversion.h>
+#include <aidl/android/hardware/tv/tuner/FrontendStatus.h>
+#include <aidl/android/hardware/tv/tuner/FrontendStatusAtsc3PlpInfo.h>
+#include <aidl/android/hardware/tv/tuner/FrontendStatusType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendTransmissionMode.h>
+#include <aidl/android/hardware/tv/tuner/FrontendType.h>
+#include <aidl/android/hardware/tv/tuner/LnbPosition.h>
+#include <aidl/android/hardware/tv/tuner/LnbTone.h>
+#include <aidl/android/hardware/tv/tuner/LnbVoltage.h>
+#include <aidl/android/hardware/tv/tuner/PlaybackSettings.h>
+#include <aidl/android/hardware/tv/tuner/RecordSettings.h>
+#include <aidl/android/hardware/tv/tuner/VideoStreamType.h>
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
-#include <utils/NativeHandle.h>
+#include <utils/Log.h>
+
+#include "android_media_MediaCodecLinearBlock.h"
+#include "android_runtime/AndroidRuntime.h"
 
 #pragma GCC diagnostic ignored "-Wunused-function"
 
-using ::android::hardware::Void;
-using ::android::hardware::hidl_bitfield;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData;
-using ::android::hardware::tv::tuner::V1_0::DataFormat;
-using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
-using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
-using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
-using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
-using ::android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
-using ::android::hardware::tv::tuner::V1_0::DemuxScHevcIndex;
-using ::android::hardware::tv::tuner::V1_0::DemuxScIndex;
-using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsIndex;
-using ::android::hardware::tv::tuner::V1_0::DvrSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Bandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3CodeRate;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3DemodOutputFormat;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Fec;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Modulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3PlpSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Settings;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3TimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcAnnex;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcOuterFec;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcSpectralInversion;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsCodeRate;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsPilot;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsRolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsVcmMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtPlpMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendInnerFec;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Coderate;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Modulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Rolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Settings;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsCoderate;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsRolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsStreamIdType;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtBandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtCoderate;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtGuardInterval;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendModulationStatus;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanAtsc3PlpInfo;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatus;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatusAtsc3PlpInfo;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
-using ::android::hardware::tv::tuner::V1_0::FrontendType;
-using ::android::hardware::tv::tuner::V1_0::LnbPosition;
-using ::android::hardware::tv::tuner::V1_0::LnbTone;
-using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
-using ::android::hardware::tv::tuner::V1_0::PlaybackSettings;
-using ::android::hardware::tv::tuner::V1_0::RecordSettings;
-using ::android::hardware::tv::tuner::V1_1::AudioStreamType;
-using ::android::hardware::tv::tuner::V1_1::AvStreamType;
-using ::android::hardware::tv::tuner::V1_1::Constant;
-using ::android::hardware::tv::tuner::V1_1::Constant64Bit;
-using ::android::hardware::tv::tuner::V1_1::FrontendAnalogAftFlag;
-using ::android::hardware::tv::tuner::V1_1::FrontendAnalogSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbcBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbsScanType;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbcSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbsSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbtSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCodeRate;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbGuardInterval;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbModulation;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbSettings;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTransmissionMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval;
-using ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendModulation;
-using ::android::hardware::tv::tuner::V1_1::FrontendRollOff;
-using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
-using ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendTransmissionMode;
-using ::android::hardware::tv::tuner::V1_1::VideoStreamType;
+using ::aidl::android::hardware::tv::tuner::AudioExtraMetaData;
+using ::aidl::android::hardware::tv::tuner::AudioStreamType;
+using ::aidl::android::hardware::tv::tuner::AvStreamType;
+using ::aidl::android::hardware::tv::tuner::Constant;
+using ::aidl::android::hardware::tv::tuner::Constant64Bit;
+using ::aidl::android::hardware::tv::tuner::DataFormat;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpLengthType;
+using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterAvSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterDownloadEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterDownloadSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterIpPayloadEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMainType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMediaEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMediaEventExtraMetaData;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMmtpRecordEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterPesDataSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterPesEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterRecordSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterScIndexMask;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionBits;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettingsCondition;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettingsConditionTableInfo;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterTemiEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterTsRecordEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxIpAddress;
+using ::aidl::android::hardware::tv::tuner::DemuxIpAddressIpAddress;
+using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxIpFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxQueueNotifyBits;
+using ::aidl::android::hardware::tv::tuner::DemuxRecordScIndexType;
+using ::aidl::android::hardware::tv::tuner::DemuxScHevcIndex;
+using ::aidl::android::hardware::tv::tuner::DemuxScIndex;
+using ::aidl::android::hardware::tv::tuner::DemuxTlvFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTlvFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTlvFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxTsIndex;
+using ::aidl::android::hardware::tv::tuner::DvrSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogAftFlag;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogSifStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogType;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Bandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3CodeRate;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3DemodOutputFormat;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Fec;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Modulation;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3PlpSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Settings;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3TimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendAtscModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendAtscSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendCableTimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbCodeRate;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbTimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcAnnex;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcOuterFec;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsCodeRate;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsPilot;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsRolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsScanType;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsVcmMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtCoderate;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtConstellation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtHierarchy;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtPlpMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::FrontendGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendInnerFec;
+using ::aidl::android::hardware::tv::tuner::FrontendInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Coderate;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Modulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Rolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Settings;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsCoderate;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsRolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsStreamIdType;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtCoderate;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtMode;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendModulationStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendRollOff;
+using ::aidl::android::hardware::tv::tuner::FrontendScanAtsc3PlpInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendSpectralInversion;
+using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusAtsc3PlpInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
+using ::aidl::android::hardware::tv::tuner::FrontendTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
+using ::aidl::android::hardware::tv::tuner::LnbPosition;
+using ::aidl::android::hardware::tv::tuner::LnbTone;
+using ::aidl::android::hardware::tv::tuner::LnbVoltage;
+using ::aidl::android::hardware::tv::tuner::PlaybackSettings;
+using ::aidl::android::hardware::tv::tuner::RecordSettings;
+using ::aidl::android::hardware::tv::tuner::VideoStreamType;
 
 struct fields_t {
     jfieldID tunerContext;
@@ -192,17 +318,16 @@
 
 static fields_t gFields;
 
-
 static int IP_V4_LENGTH = 4;
 static int IP_V6_LENGTH = 16;
 
 void DestroyCallback(const C2Buffer * buf, void *arg) {
     android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
     android::Mutex::Autolock autoLock(event->mLock);
-    if (event->mLinearBlockObj != NULL) {
+    if (event->mLinearBlockObj != nullptr) {
         JNIEnv *env = android::AndroidRuntime::getJNIEnv();
         env->DeleteWeakGlobalRef(event->mLinearBlockObj);
-        event->mLinearBlockObj = NULL;
+        event->mLinearBlockObj = nullptr;
     }
 
     event->mAvHandleRefCnt--;
@@ -211,11 +336,9 @@
 }
 
 namespace android {
-
 /////////////// LnbClientCallbackImpl ///////////////////////
-
 void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) {
-    ALOGD("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType);
+    ALOGV("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject lnb(env->NewLocalRef(mLnbObj));
     if (!env->IsSameObject(lnb, nullptr)) {
@@ -229,14 +352,14 @@
     }
 }
 
-void LnbClientCallbackImpl::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
-    ALOGD("LnbClientCallbackImpl::onDiseqcMessage");
+void LnbClientCallbackImpl::onDiseqcMessage(const vector<uint8_t> &diseqcMessage) {
+    ALOGV("LnbClientCallbackImpl::onDiseqcMessage");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject lnb(env->NewLocalRef(mLnbObj));
     if (!env->IsSameObject(lnb, nullptr)) {
         jbyteArray array = env->NewByteArray(diseqcMessage.size());
-        env->SetByteArrayRegion(
-                array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0]));
+        env->SetByteArrayRegion(array, 0, diseqcMessage.size(),
+                                reinterpret_cast<const jbyte *>(&diseqcMessage[0]));
         env->CallVoidMethod(
                 lnb,
                 gFields.onLnbDiseqcMessageID,
@@ -248,22 +371,21 @@
 }
 
 void LnbClientCallbackImpl::setLnb(jweak lnbObj) {
-    ALOGD("LnbClientCallbackImpl::setLnb");
+    ALOGV("LnbClientCallbackImpl::setLnb");
     mLnbObj = lnbObj;
 }
 
 LnbClientCallbackImpl::~LnbClientCallbackImpl() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (mLnbObj != NULL) {
+    if (mLnbObj != nullptr) {
         env->DeleteWeakGlobalRef(mLnbObj);
-        mLnbObj = NULL;
+        mLnbObj = nullptr;
     }
 }
 
 /////////////// DvrClientCallbackImpl ///////////////////////
-
 void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) {
-    ALOGD("DvrClientCallbackImpl::onRecordStatus");
+    ALOGV("DvrClientCallbackImpl::onRecordStatus");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject dvr(env->NewLocalRef(mDvrObj));
     if (!env->IsSameObject(dvr, nullptr)) {
@@ -278,7 +400,7 @@
 }
 
 void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) {
-    ALOGD("DvrClientCallbackImpl::onPlaybackStatus");
+    ALOGV("DvrClientCallbackImpl::onPlaybackStatus");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject dvr(env->NewLocalRef(mDvrObj));
     if (!env->IsSameObject(dvr, nullptr)) {
@@ -293,20 +415,19 @@
 }
 
 void DvrClientCallbackImpl::setDvr(jweak dvrObj) {
-    ALOGD("DvrClientCallbackImpl::setDvr");
+    ALOGV("DvrClientCallbackImpl::setDvr");
     mDvrObj = dvrObj;
 }
 
 DvrClientCallbackImpl::~DvrClientCallbackImpl() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (mDvrObj != NULL) {
+    if (mDvrObj != nullptr) {
         env->DeleteWeakGlobalRef(mDvrObj);
-        mDvrObj = NULL;
+        mDvrObj = nullptr;
     }
 }
 
 /////////////// C2DataIdInfo ///////////////////////
-
 C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
     CHECK(isGlobal());
     CHECK_EQ(C2Param::INFO, kind());
@@ -316,40 +437,44 @@
 }
 
 /////////////// MediaEvent ///////////////////////
-
-MediaEvent::MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle,
-        uint64_t dataId, uint64_t dataSize, jobject obj) : mFilterClient(filterClient),
-        mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr),
-        mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
+MediaEvent::MediaEvent(sp<FilterClient> filterClient, native_handle_t *avHandle, uint64_t dataId,
+                       uint64_t dataSize, jobject obj)
+      : mFilterClient(filterClient),
+        mDataId(dataId),
+        mDataSize(dataSize),
+        mBuffer(nullptr),
+        mDataIdRefCnt(0),
+        mAvHandleRefCnt(0),
+        mIonHandle(nullptr) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     mMediaEventObj = env->NewWeakGlobalRef(obj);
-    mAvHandle = native_handle_clone(avHandle.getNativeHandle());
-    mLinearBlockObj = NULL;
+    mAvHandle = avHandle;
+    mLinearBlockObj = nullptr;
 }
 
 MediaEvent::~MediaEvent() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     env->DeleteWeakGlobalRef(mMediaEventObj);
-    mMediaEventObj = NULL;
+    mMediaEventObj = nullptr;
     native_handle_delete(mAvHandle);
-    if (mIonHandle != NULL) {
+    if (mIonHandle != nullptr) {
         delete mIonHandle;
     }
     std::shared_ptr<C2Buffer> pC2Buffer = mC2Buffer.lock();
-    if (pC2Buffer != NULL) {
+    if (pC2Buffer != nullptr) {
         pC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this);
     }
 
-    if (mLinearBlockObj != NULL) {
+    if (mLinearBlockObj != nullptr) {
         env->DeleteWeakGlobalRef(mLinearBlockObj);
-        mLinearBlockObj = NULL;
+        mLinearBlockObj = nullptr;
     }
 
-    mFilterClient = NULL;
+    mFilterClient = nullptr;
 }
 
 void MediaEvent::finalize() {
-    if (mAvHandleRefCnt == 0 && mFilterClient != NULL) {
+    if (mAvHandleRefCnt == 0 && mFilterClient != nullptr) {
         mFilterClient->releaseAvHandle(
                 mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0);
         native_handle_close(mAvHandle);
@@ -357,11 +482,11 @@
 }
 
 jobject MediaEvent::getLinearBlock() {
-    ALOGD("MediaEvent::getLinearBlock");
-    if (mAvHandle == NULL) {
-        return NULL;
+    ALOGV("MediaEvent::getLinearBlock");
+    if (mAvHandle == nullptr) {
+        return nullptr;
     }
-    if (mLinearBlockObj != NULL) {
+    if (mLinearBlockObj != nullptr) {
         return mLinearBlockObj;
     }
 
@@ -374,13 +499,13 @@
     uint64_t avSharedMemSize = info.size;
 
     if (mAvHandle->numFds == 0) {
-        if (avSharedHandle == NULL) {
+        if (avSharedHandle == nullptr) {
             ALOGE("Shared AV memory handle is not initialized.");
-            return NULL;
+            return nullptr;
         }
         if (avSharedHandle->numFds == 0) {
             ALOGE("Shared AV memory handle is empty.");
-            return NULL;
+            return nullptr;
         }
         fd = avSharedHandle->data[0];
         dataSize = avSharedMemSize;
@@ -398,7 +523,7 @@
             // event has value, use it as the index
             memIndex = mAvHandle->data[mAvHandle->numFds];
         } else {
-            if (avSharedHandle != NULL) {
+            if (avSharedHandle != nullptr) {
                 numInts = avSharedHandle->numInts;
                 if (numInts > 0) {
                     // If the first int in the shared native handle has value, use it as the index
@@ -413,7 +538,7 @@
     if (block != nullptr) {
         // CreateLinearBlock delete mIonHandle after it create block successfully.
         // ToDo: coordinate who is response to delete mIonHandle
-        mIonHandle = NULL;
+        mIonHandle = nullptr;
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
         context->mBlock = block;
@@ -444,8 +569,8 @@
                     reinterpret_cast<const native_handle_t*>(mIonHandle)));
         native_handle_delete(const_cast<native_handle_t*>(
                     reinterpret_cast<const native_handle_t*>(mIonHandle)));
-        mIonHandle = NULL;
-        return NULL;
+        mIonHandle = nullptr;
+        return nullptr;
     }
 }
 
@@ -455,31 +580,24 @@
 }
 
 /////////////// FilterClientCallbackImpl ///////////////////////
-
-jobjectArray FilterClientCallbackImpl::getSectionEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getSectionEvent(jobjectArray &arr, const int size,
+                                               const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIII)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterSectionEvent sectionEvent = event.section();
+    const DemuxFilterSectionEvent &sectionEvent = event.get<DemuxFilterEvent::Tag::section>();
+    jint tableId = static_cast<jint>(sectionEvent.tableId);
+    jint version = static_cast<jint>(sectionEvent.version);
+    jint sectionNum = static_cast<jint>(sectionEvent.sectionNum);
+    jint dataLength = static_cast<jint>(sectionEvent.dataLength);
 
-        jint tableId = static_cast<jint>(sectionEvent.tableId);
-        jint version = static_cast<jint>(sectionEvent.version);
-        jint sectionNum = static_cast<jint>(sectionEvent.sectionNum);
-        jint dataLength = static_cast<jint>(sectionEvent.dataLength);
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    jobject obj = env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getMediaEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size,
+                                             const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz,
@@ -488,353 +606,284 @@
             "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
     jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterMediaEvent mediaEvent = event.media();
+    const DemuxFilterMediaEvent &mediaEvent = event.get<DemuxFilterEvent::Tag::media>();
+    jobject audioDescriptor = nullptr;
+    if (mediaEvent.extraMetaData.getTag() == DemuxFilterMediaEventExtraMetaData::Tag::audio) {
+        jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor");
+        jmethodID adInit = env->GetMethodID(adClazz, "<init>", "(BBCBBB)V");
 
-        jobject audioDescriptor = NULL;
-        if (mediaEvent.extraMetaData.getDiscriminator()
-                == DemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
-            jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor");
-            jmethodID adInit = env->GetMethodID(adClazz, "<init>", "(BBCBBB)V");
+        const AudioExtraMetaData &ad =
+                mediaEvent.extraMetaData.get<DemuxFilterMediaEventExtraMetaData::Tag::audio>();
+        jbyte adFade = static_cast<jbyte>(ad.adFade);
+        jbyte adPan = static_cast<jbyte>(ad.adPan);
+        jchar versionTextTag = static_cast<jchar>(ad.versionTextTag);
+        jbyte adGainCenter = static_cast<jbyte>(ad.adGainCenter);
+        jbyte adGainFront = static_cast<jbyte>(ad.adGainFront);
+        jbyte adGainSurround = static_cast<jbyte>(ad.adGainSurround);
 
-            AudioExtraMetaData ad = mediaEvent.extraMetaData.audio();
-            jbyte adFade = static_cast<jbyte>(ad.adFade);
-            jbyte adPan = static_cast<jbyte>(ad.adPan);
-            jchar versionTextTag = static_cast<jchar>(ad.versionTextTag);
-            jbyte adGainCenter = static_cast<jbyte>(ad.adGainCenter);
-            jbyte adGainFront = static_cast<jbyte>(ad.adGainFront);
-            jbyte adGainSurround = static_cast<jbyte>(ad.adGainSurround);
-
-            audioDescriptor =
-                    env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, adGainCenter,
-                            adGainFront, adGainSurround);
-        }
-
-        jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
-
-        jint streamId = static_cast<jint>(mediaEvent.streamId);
-        jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
-        jlong pts = static_cast<jlong>(mediaEvent.pts);
-        jlong offset = static_cast<jlong>(mediaEvent.offset);
-        jboolean isSecureMemory = static_cast<jboolean>(mediaEvent.isSecureMemory);
-        jlong avDataId = static_cast<jlong>(mediaEvent.avDataId);
-        jint mpuSequenceNumber = static_cast<jint>(mediaEvent.mpuSequenceNumber);
-        jboolean isPesPrivateData = static_cast<jboolean>(mediaEvent.isPesPrivateData);
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
-                offset, NULL, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
-                audioDescriptor);
-
-        if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
-            sp<MediaEvent> mediaEventSp =
-                           new MediaEvent(mFilterClient, mediaEvent.avMemory,
-                               mediaEvent.avDataId, dataLength + offset, obj);
-            mediaEventSp->mAvHandleRefCnt++;
-            env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
-            mediaEventSp->incStrong(obj);
-        }
-
-        env->SetObjectArrayElement(arr, i, obj);
+        audioDescriptor = env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag,
+                                         adGainCenter, adGainFront, adGainSurround);
     }
-    return arr;
+
+    jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
+    jint streamId = static_cast<jint>(mediaEvent.streamId);
+    jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
+    jlong pts = static_cast<jlong>(mediaEvent.pts);
+    jlong offset = static_cast<jlong>(mediaEvent.offset);
+    jboolean isSecureMemory = static_cast<jboolean>(mediaEvent.isSecureMemory);
+    jlong avDataId = static_cast<jlong>(mediaEvent.avDataId);
+    jint mpuSequenceNumber = static_cast<jint>(mediaEvent.mpuSequenceNumber);
+    jboolean isPesPrivateData = static_cast<jboolean>(mediaEvent.isPesPrivateData);
+
+    jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
+                                 offset, nullptr, isSecureMemory, avDataId, mpuSequenceNumber,
+                                 isPesPrivateData, audioDescriptor);
+
+    if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0) {
+        sp<MediaEvent> mediaEventSp =
+                new MediaEvent(mFilterClient, makeFromAidl(mediaEvent.avMemory),
+                               mediaEvent.avDataId, dataLength + offset, obj);
+        mediaEventSp->mAvHandleRefCnt++;
+        env->SetLongField(obj, eventContext, (jlong)mediaEventSp.get());
+        mediaEventSp->incStrong(obj);
+    }
+
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getPesEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getPesEvent(jobjectArray &arr, const int size,
+                                           const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(III)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterPesEvent pesEvent = event.pes();
+    const DemuxFilterPesEvent &pesEvent = event.get<DemuxFilterEvent::Tag::pes>();
+    jint streamId = static_cast<jint>(pesEvent.streamId);
+    jint dataLength = static_cast<jint>(pesEvent.dataLength);
+    jint mpuSequenceNumber = static_cast<jint>(pesEvent.mpuSequenceNumber);
 
-        jint streamId = static_cast<jint>(pesEvent.streamId);
-        jint dataLength = static_cast<jint>(pesEvent.dataLength);
-        jint mpuSequenceNumber = static_cast<jint>(pesEvent.mpuSequenceNumber);
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    jobject obj = env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getTsRecordEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
-                const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
+void FilterClientCallbackImpl::getTsRecordEvent(jobjectArray &arr, const int size,
+                                                const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJJI)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterTsRecordEvent tsRecordEvent = event.tsRecord();
-        DemuxPid pid = tsRecordEvent.pid;
+    const DemuxFilterTsRecordEvent &tsRecordEvent = event.get<DemuxFilterEvent::Tag::tsRecord>();
+    DemuxPid pid = tsRecordEvent.pid;
 
-        jint jpid = static_cast<jint>(Constant::INVALID_TS_PID);
-
-        if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
-            jpid = static_cast<jint>(pid.tPid());
-        } else if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::mmtpPid) {
-            jpid = static_cast<jint>(pid.mmtpPid());
-        }
-
-        jint sc = 0;
-
-        if (tsRecordEvent.scIndexMask.getDiscriminator()
-                == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) {
-            sc = static_cast<jint>(tsRecordEvent.scIndexMask.sc());
-        } else if (tsRecordEvent.scIndexMask.getDiscriminator()
-                == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) {
-            sc = static_cast<jint>(tsRecordEvent.scIndexMask.scHevc());
-        }
-
-        jint ts = static_cast<jint>(tsRecordEvent.tsIndexMask);
-
-        jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
-
-        jlong pts;
-        jlong firstMbInSlice;
-        if (eventsExt.size() > i && eventsExt[i].getDiscriminator() ==
-                    DemuxFilterEventExt::Event::hidl_discriminator::tsRecord) {
-            pts = static_cast<jlong>(eventsExt[i].tsRecord().pts);
-            firstMbInSlice = static_cast<jint>(eventsExt[i].tsRecord().firstMbInSlice);
-        } else {
-            pts = static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
-            firstMbInSlice = static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
-        }
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber,
-                        pts, firstMbInSlice);
-        env->SetObjectArrayElement(arr, i, obj);
+    jint jpid = static_cast<jint>(Constant::INVALID_TS_PID);
+    if (pid.getTag() == DemuxPid::Tag::tPid) {
+        jpid = static_cast<jint>(pid.get<DemuxPid::Tag::tPid>());
+    } else if (pid.getTag() == DemuxPid::Tag::mmtpPid) {
+        jpid = static_cast<jint>(pid.get<DemuxPid::Tag::mmtpPid>());
     }
-    return arr;
+
+    jint sc = 0;
+    if (tsRecordEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scIndex) {
+        sc = static_cast<jint>(
+                tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scIndex>());
+    } else if (tsRecordEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scHevc) {
+        sc = static_cast<jint>(
+                tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scHevc>());
+    }
+
+    jint ts = static_cast<jint>(tsRecordEvent.tsIndexMask);
+    jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
+    jlong pts = static_cast<jlong>(tsRecordEvent.pts);
+    jint firstMbInSlice = static_cast<jint>(tsRecordEvent.firstMbInSlice);
+
+    jobject obj =
+            env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber, pts, firstMbInSlice);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getMmtpRecordEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
-                const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
+void FilterClientCallbackImpl::getMmtpRecordEvent(jobjectArray &arr, const int size,
+                                                  const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJIJII)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
+    const DemuxFilterMmtpRecordEvent &mmtpRecordEvent =
+            event.get<DemuxFilterEvent::Tag::mmtpRecord>();
+    jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
+    jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
+    jint mpuSequenceNumber = static_cast<jint>(mmtpRecordEvent.mpuSequenceNumber);
+    jlong pts = static_cast<jlong>(mmtpRecordEvent.pts);
+    jint firstMbInSlice = static_cast<jint>(mmtpRecordEvent.firstMbInSlice);
+    jlong tsIndexMask = static_cast<jlong>(mmtpRecordEvent.tsIndexMask);
 
-        DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord();
-
-        jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
-        jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
-
-        jint mpuSequenceNumber;
-        jlong pts;
-        jlong firstMbInSlice;
-        jlong tsIndexMask;
-
-        if (eventsExt.size() > i && eventsExt[i].getDiscriminator() ==
-                    DemuxFilterEventExt::Event::hidl_discriminator::mmtpRecord) {
-            mpuSequenceNumber = static_cast<jint>(eventsExt[i].mmtpRecord().mpuSequenceNumber);
-            pts = static_cast<jlong>(eventsExt[i].mmtpRecord().pts);
-            firstMbInSlice = static_cast<jint>(eventsExt[i].mmtpRecord().firstMbInSlice);
-            tsIndexMask = static_cast<jint>(eventsExt[i].mmtpRecord().tsIndexMask);
-        } else {
-            mpuSequenceNumber =
-                    static_cast<jint>(Constant::INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
-            pts = static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
-            firstMbInSlice = static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
-            tsIndexMask = 0;
-        }
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
-                        mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    jobject obj = env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
+                                 mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getDownloadEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getDownloadEvent(jobjectArray &arr, const int size,
+                                                const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIII)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterDownloadEvent downloadEvent = event.download();
+    const DemuxFilterDownloadEvent &downloadEvent = event.get<DemuxFilterEvent::Tag::download>();
+    jint itemId = static_cast<jint>(downloadEvent.itemId);
+    jint mpuSequenceNumber = static_cast<jint>(downloadEvent.mpuSequenceNumber);
+    jint itemFragmentIndex = static_cast<jint>(downloadEvent.itemFragmentIndex);
+    jint lastItemFragmentIndex = static_cast<jint>(downloadEvent.lastItemFragmentIndex);
+    jint dataLength = static_cast<jint>(downloadEvent.dataLength);
 
-        jint itemId = static_cast<jint>(downloadEvent.itemId);
-        jint mpuSequenceNumber = static_cast<jint>(downloadEvent.mpuSequenceNumber);
-        jint itemFragmentIndex = static_cast<jint>(downloadEvent.itemFragmentIndex);
-        jint lastItemFragmentIndex = static_cast<jint>(downloadEvent.lastItemFragmentIndex);
-        jint dataLength = static_cast<jint>(downloadEvent.dataLength);
-
-        jobject obj =
-                env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber, itemFragmentIndex,
-                        lastItemFragmentIndex, dataLength);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    jobject obj = env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber,
+                                 itemFragmentIndex, lastItemFragmentIndex, dataLength);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getIpPayloadEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getIpPayloadEvent(jobjectArray &arr, const int size,
+                                                 const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterIpPayloadEvent ipPayloadEvent = event.ipPayload();
-        jint dataLength = static_cast<jint>(ipPayloadEvent.dataLength);
-        jobject obj = env->NewObject(eventClazz, eventInit, dataLength);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    const DemuxFilterIpPayloadEvent &ipPayloadEvent = event.get<DemuxFilterEvent::Tag::ipPayload>();
+    jint dataLength = static_cast<jint>(ipPayloadEvent.dataLength);
+    jobject obj = env->NewObject(eventClazz, eventInit, dataLength);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getTemiEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+void FilterClientCallbackImpl::getTemiEvent(jobjectArray &arr, const int size,
+                                            const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(JB[B)V");
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        DemuxFilterTemiEvent temiEvent = event.temi();
-        jlong pts = static_cast<jlong>(temiEvent.pts);
-        jbyte descrTag = static_cast<jbyte>(temiEvent.descrTag);
-        std::vector<uint8_t> descrData = temiEvent.descrData;
+    const DemuxFilterTemiEvent &temiEvent = event.get<DemuxFilterEvent::Tag::temi>();
+    jlong pts = static_cast<jlong>(temiEvent.pts);
+    jbyte descrTag = static_cast<jbyte>(temiEvent.descrTag);
+    std::vector<uint8_t> descrData = temiEvent.descrData;
 
-        jbyteArray array = env->NewByteArray(descrData.size());
-        env->SetByteArrayRegion(
-                array, 0, descrData.size(), reinterpret_cast<jbyte*>(&descrData[0]));
+    jbyteArray array = env->NewByteArray(descrData.size());
+    env->SetByteArrayRegion(array, 0, descrData.size(), reinterpret_cast<jbyte *>(&descrData[0]));
 
-        jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array);
-        env->SetObjectArrayElement(arr, i, obj);
-    }
-    return arr;
+    jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getScramblingStatusEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
+void FilterClientCallbackImpl::getScramblingStatusEvent(jobjectArray &arr, const int size,
+                                                        const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/ScramblingStatusEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
 
-    auto scramblingStatus = eventsExt[0].monitorEvent().scramblingStatus();
-    jobject obj = env->NewObject(eventClazz, eventInit, static_cast<jint>(scramblingStatus));
-    env->SetObjectArrayElement(arr, 0, obj);
-    return arr;
+    const DemuxFilterMonitorEvent &scramblingStatus =
+            event.get<DemuxFilterEvent::Tag::monitorEvent>()
+                    .get<DemuxFilterMonitorEvent::Tag::scramblingStatus>();
+    jobject obj = env->NewObject(eventClazz, eventInit, scramblingStatus);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getIpCidChangeEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
+void FilterClientCallbackImpl::getIpCidChangeEvent(jobjectArray &arr, const int size,
+                                                   const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpCidChangeEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
 
-    auto cid = eventsExt[0].monitorEvent().cid();
-    jobject obj = env->NewObject(eventClazz, eventInit, static_cast<jint>(cid));
-    env->SetObjectArrayElement(arr, 0, obj);
-    return arr;
+    const DemuxFilterMonitorEvent &cid = event.get<DemuxFilterEvent::Tag::monitorEvent>()
+                                                 .get<DemuxFilterMonitorEvent::Tag::cid>();
+    jobject obj = env->NewObject(eventClazz, eventInit, cid);
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-jobjectArray FilterClientCallbackImpl::getRestartEvent(
-        jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
+void FilterClientCallbackImpl::getRestartEvent(jobjectArray &arr, const int size,
+                                               const DemuxFilterEvent &event) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/RestartEvent");
     jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
 
-    auto startId = eventsExt[0].startId();
+    const int32_t &startId = event.get<DemuxFilterEvent::Tag::startId>();
     jobject obj = env->NewObject(eventClazz, eventInit, static_cast<jint>(startId));
-    env->SetObjectArrayElement(arr, 0, obj);
-    return arr;
+    env->SetObjectArrayElement(arr, size, obj);
 }
 
-void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
-        const DemuxFilterEventExt& filterEventExt) {
-    ALOGD("FilterClientCallbackImpl::onFilterEvent_1_1");
-
+void FilterClientCallbackImpl::onFilterEvent(const vector<DemuxFilterEvent> &events) {
+    ALOGV("FilterClientCallbackImpl::onFilterEvent");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
     jobjectArray array;
 
-    std::vector<DemuxFilterEvent::Event> events = filterEvent.events;
-    std::vector<DemuxFilterEventExt::Event> eventsExt = filterEventExt.events;
-    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
+    if (!events.empty()) {
+        array = env->NewObjectArray(events.size(), eventClazz, nullptr);
+    }
 
-    if (events.empty() && !eventsExt.empty()) {
-        // Monitor event should be sent with one DemuxFilterMonitorEvent in DemuxFilterEventExt.
-        array = env->NewObjectArray(1, eventClazz, NULL);
-        auto eventExt = eventsExt[0];
-        switch (eventExt.getDiscriminator()) {
-            case DemuxFilterEventExt::Event::hidl_discriminator::monitorEvent: {
-                switch (eventExt.monitorEvent().getDiscriminator()) {
-                    case DemuxFilterMonitorEvent::hidl_discriminator::scramblingStatus: {
-                        array = getScramblingStatusEvent(array, eventsExt);
+    for (int i = 0, arraySize = 0; i < events.size(); i++) {
+        const DemuxFilterEvent &event = events[i];
+        switch (event.getTag()) {
+            case DemuxFilterEvent::Tag::media: {
+                getMediaEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::section: {
+                getSectionEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::pes: {
+                getPesEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::tsRecord: {
+                getTsRecordEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::mmtpRecord: {
+                getMmtpRecordEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::download: {
+                getDownloadEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::ipPayload: {
+                getIpPayloadEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::temi: {
+                getTemiEvent(array, arraySize, event);
+                arraySize++;
+                break;
+            }
+            case DemuxFilterEvent::Tag::monitorEvent: {
+                switch (event.get<DemuxFilterEvent::Tag::monitorEvent>().getTag()) {
+                    case DemuxFilterMonitorEvent::Tag::scramblingStatus: {
+                        getScramblingStatusEvent(array, arraySize, event);
+                        arraySize++;
                         break;
                     }
-                    case DemuxFilterMonitorEvent::hidl_discriminator::cid: {
-                        array = getIpCidChangeEvent(array, eventsExt);
+                    case DemuxFilterMonitorEvent::Tag::cid: {
+                        getIpCidChangeEvent(array, arraySize, event);
+                        arraySize++;
                         break;
                     }
                     default: {
+                        ALOGE("FilterClientCallbackImpl::onFilterEvent: unknown MonitorEvent");
                         break;
                     }
                 }
                 break;
             }
-            case DemuxFilterEventExt::Event::hidl_discriminator::startId: {
-                array = getRestartEvent(array, eventsExt);
+            case DemuxFilterEvent::Tag::startId: {
+                getRestartEvent(array, arraySize, event);
+                arraySize++;
                 break;
             }
             default: {
-                break;
-            }
-        }
-    }
-
-    if (!events.empty()) {
-        array = env->NewObjectArray(events.size(), eventClazz, NULL);
-        auto event = events[0];
-        switch (event.getDiscriminator()) {
-            case DemuxFilterEvent::Event::hidl_discriminator::media: {
-                array = getMediaEvent(array, events);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::section: {
-                array = getSectionEvent(array, events);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::pes: {
-                array = getPesEvent(array, events);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
-                array = getTsRecordEvent(array, events, eventsExt);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
-                array = getMmtpRecordEvent(array, events, eventsExt);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::download: {
-                array = getDownloadEvent(array, events);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::ipPayload: {
-                array = getIpPayloadEvent(array, events);
-                break;
-            }
-            case DemuxFilterEvent::Event::hidl_discriminator::temi: {
-                array = getTemiEvent(array, events);
-                break;
-            }
-            default: {
+                ALOGE("FilterClientCallbackImpl::onFilterEvent: unknown DemuxFilterEvent");
                 break;
             }
         }
@@ -846,22 +895,13 @@
                 gFields.onFilterEventID,
                 array);
     } else {
-        ALOGE("FilterClientCallbackImpl::onFilterEvent_1_1:"
-                "Filter object has been freed. Ignoring callback.");
+        ALOGE("FilterClientCallbackImpl::onFilterEvent:"
+              "Filter object has been freed. Ignoring callback.");
     }
 }
 
-void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) {
-    ALOGD("FilterClientCallbackImpl::onFilterEvent");
-    std::vector<DemuxFilterEventExt::Event> emptyEventsExt;
-    DemuxFilterEventExt emptyFilterEventExt {
-            .events = emptyEventsExt,
-    };
-    return onFilterEvent_1_1(filterEvent, emptyFilterEventExt);
-}
-
 void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
-    ALOGD("FilterClientCallbackImpl::onFilterStatus");
+    ALOGV("FilterClientCallbackImpl::onFilterStatus");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject filter(env->NewLocalRef(mFilterObj));
     if (!env->IsSameObject(filter, nullptr)) {
@@ -876,7 +916,7 @@
 }
 
 void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) {
-    ALOGD("FilterClientCallbackImpl::setFilter");
+    ALOGV("FilterClientCallbackImpl::setFilter");
     // Java Object
     mFilterObj = filterObj;
     mFilterClient = filterClient;
@@ -884,19 +924,18 @@
 
 FilterClientCallbackImpl::~FilterClientCallbackImpl() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (mFilterObj != NULL) {
+    if (mFilterObj != nullptr) {
         env->DeleteWeakGlobalRef(mFilterObj);
-        mFilterObj = NULL;
+        mFilterObj = nullptr;
     }
-    mFilterClient = NULL;
+    mFilterClient = nullptr;
 }
 
 /////////////// FrontendClientCallbackImpl ///////////////////////
-
 FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject(tunerObj) {}
 
 void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) {
-    ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType);
+    ALOGV("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobject frontend(env->NewLocalRef(mObject));
     if (!env->IsSameObject(frontend, nullptr)) {
@@ -912,7 +951,7 @@
 
 void FrontendClientCallbackImpl::onScanMessage(
         FrontendScanMessageType type, const FrontendScanMessage& message) {
-    ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
+    ALOGV("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
     jobject frontend(env->NewLocalRef(mObject));
@@ -923,7 +962,7 @@
     }
     switch(type) {
         case FrontendScanMessageType::LOCKED: {
-            if (message.isLocked()) {
+            if (message.get<FrontendScanMessage::Tag::isLocked>()) {
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onLocked", "()V"));
@@ -931,7 +970,7 @@
             break;
         }
         case FrontendScanMessageType::END: {
-            if (message.isEnd()) {
+            if (message.get<FrontendScanMessage::Tag::isEnd>()) {
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onScanStopped", "()V"));
@@ -939,14 +978,12 @@
             break;
         }
         case FrontendScanMessageType::PROGRESS_PERCENT: {
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onProgress", "(I)V"),
-                    (jint) message.progressPercent());
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onProgress", "(I)V"),
+                                (jint)message.get<FrontendScanMessage::Tag::progressPercent>());
             break;
         }
         case FrontendScanMessageType::FREQUENCY: {
-            std::vector<uint32_t> v = message.frequencies();
+            std::vector<int32_t> v = message.get<FrontendScanMessage::Tag::frequencies>();
             jintArray freqs = env->NewIntArray(v.size());
             env->SetIntArrayRegion(freqs, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
 
@@ -957,7 +994,7 @@
             break;
         }
         case FrontendScanMessageType::SYMBOL_RATE: {
-            std::vector<uint32_t> v = message.symbolRates();
+            std::vector<int32_t> v = message.get<FrontendScanMessage::Tag::symbolRates>();
             jintArray symbolRates = env->NewIntArray(v.size());
             env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
 
@@ -968,21 +1005,17 @@
             break;
         }
         case FrontendScanMessageType::HIERARCHY: {
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onHierarchy", "(I)V"),
-                    (jint) message.hierarchy());
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onHierarchy", "(I)V"),
+                                (jint)message.get<FrontendScanMessage::Tag::hierarchy>());
             break;
         }
         case FrontendScanMessageType::ANALOG_TYPE: {
-            env->CallVoidMethod(
-                    frontend,
-                    env->GetMethodID(clazz, "onSignalType", "(I)V"),
-                    (jint) message.analogType());
+            env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onSignalType", "(I)V"),
+                                (jint)message.get<FrontendScanMessage::Tag::analogType>());
             break;
         }
         case FrontendScanMessageType::PLP_IDS: {
-            std::vector<uint8_t> v = message.plpIds();
+            std::vector<uint8_t> v = message.get<FrontendScanMessage::Tag::plpIds>();
             std::vector<jint> jintV(v.begin(), v.end());
             jintArray plpIds = env->NewIntArray(v.size());
             env->SetIntArrayRegion(plpIds, 0, jintV.size(), &jintV[0]);
@@ -994,7 +1027,7 @@
             break;
         }
         case FrontendScanMessageType::GROUP_IDS: {
-            std::vector<uint8_t> v = message.groupIds();
+            std::vector<uint8_t> v = message.get<FrontendScanMessage::groupIds>();
             std::vector<jint> jintV(v.begin(), v.end());
             jintArray groupIds = env->NewIntArray(v.size());
             env->SetIntArrayRegion(groupIds, 0, jintV.size(), &jintV[0]);
@@ -1006,7 +1039,7 @@
             break;
         }
         case FrontendScanMessageType::INPUT_STREAM_IDS: {
-            std::vector<uint16_t> v = message.inputStreamIds();
+            std::vector<char16_t> v = message.get<FrontendScanMessage::inputStreamIds>();
             std::vector<jint> jintV(v.begin(), v.end());
             jintArray streamIds = env->NewIntArray(v.size());
             env->SetIntArrayRegion(streamIds, 0, jintV.size(), &jintV[0]);
@@ -1018,24 +1051,22 @@
             break;
         }
         case FrontendScanMessageType::STANDARD: {
-            FrontendScanMessage::Standard std = message.std();
+            FrontendScanMessageStandard std = message.get<FrontendScanMessage::std>();
             jint standard;
-            if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sStd) {
-                standard = (jint) std.sStd();
+            if (std.getTag() == FrontendScanMessageStandard::Tag::sStd) {
+                standard = (jint)std.get<FrontendScanMessageStandard::Tag::sStd>();
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onDvbsStandard", "(I)V"),
                         standard);
-            } else if (std.getDiscriminator() ==
-                    FrontendScanMessage::Standard::hidl_discriminator::tStd) {
-                standard = (jint) std.tStd();
+            } else if (std.getTag() == FrontendScanMessageStandard::Tag::tStd) {
+                standard = (jint)std.get<FrontendScanMessageStandard::Tag::tStd>();
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
                         standard);
-            } else if (std.getDiscriminator() ==
-                    FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
-                standard = (jint) std.sifStd();
+            } else if (std.getTag() == FrontendScanMessageStandard::Tag::sifStd) {
+                standard = (jint)std.get<FrontendScanMessageStandard::Tag::sifStd>();
                 env->CallVoidMethod(
                         frontend,
                         env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"),
@@ -1046,8 +1077,9 @@
         case FrontendScanMessageType::ATSC3_PLP_INFO: {
             jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo");
             jmethodID init = env->GetMethodID(plpClazz, "<init>", "(IZ)V");
-            std::vector<FrontendScanAtsc3PlpInfo> plpInfos = message.atsc3PlpInfos();
-            jobjectArray array = env->NewObjectArray(plpInfos.size(), plpClazz, NULL);
+            std::vector<FrontendScanAtsc3PlpInfo> plpInfos =
+                    message.get<FrontendScanMessage::atsc3PlpInfos>();
+            jobjectArray array = env->NewObjectArray(plpInfos.size(), plpClazz, nullptr);
 
             for (int i = 0; i < plpInfos.size(); i++) {
                 auto info = plpInfos[i];
@@ -1064,82 +1096,67 @@
                     array);
             break;
         }
-    }
-}
-
-void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
-        const FrontendScanMessageExt1_1& message) {
-    ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type);
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
-    jobject frontend(env->NewLocalRef(mObject));
-    if (env->IsSameObject(frontend, nullptr)) {
-        ALOGE("FrontendClientCallbackImpl::onScanMessageExt1_1:"
-                "Frontend object has been freed. Ignoring callback.");
-        return;
-    }
-    switch(type) {
-        case FrontendScanMessageTypeExt1_1::MODULATION: {
-            jint modulation = -1;
-            switch (message.modulation().getDiscriminator()) {
-                case FrontendModulation::hidl_discriminator::dvbc: {
-                    modulation = (jint) message.modulation().dvbc();
+        case FrontendScanMessageType::MODULATION: {
+            jint modulationType = -1;
+            FrontendModulation modulation = message.get<FrontendScanMessage::modulation>();
+            switch (modulation.getTag()) {
+                case FrontendModulation::Tag::dvbc: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::dvbc>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::dvbt: {
-                    modulation = (jint) message.modulation().dvbt();
+                case FrontendModulation::Tag::dvbt: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::dvbt>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::dvbs: {
-                    modulation = (jint) message.modulation().dvbs();
+                case FrontendModulation::Tag::dvbs: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::dvbs>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::isdbs: {
-                    modulation = (jint) message.modulation().isdbs();
+                case FrontendModulation::Tag::isdbs: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::isdbs>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::isdbs3: {
-                    modulation = (jint) message.modulation().isdbs3();
+                case FrontendModulation::Tag::isdbs3: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::isdbs3>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::isdbt: {
-                    modulation = (jint) message.modulation().isdbt();
+                case FrontendModulation::Tag::isdbt: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::isdbt>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::atsc: {
-                    modulation = (jint) message.modulation().atsc();
+                case FrontendModulation::Tag::atsc: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::atsc>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::atsc3: {
-                    modulation = (jint) message.modulation().atsc3();
+                case FrontendModulation::Tag::atsc3: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::atsc3>();
                     break;
                 }
-                case FrontendModulation::hidl_discriminator::dtmb: {
-                    modulation = (jint) message.modulation().dtmb();
+                case FrontendModulation::Tag::dtmb: {
+                    modulationType = (jint)modulation.get<FrontendModulation::Tag::dtmb>();
                     break;
                 }
                 default: {
                     break;
                 }
             }
-            if (modulation > 0) {
-                env->CallVoidMethod(
-                        frontend,
-                        env->GetMethodID(clazz, "onModulationReported", "(I)V"),
-                        modulation);
+            if (modulationType > 0) {
+                env->CallVoidMethod(frontend,
+                                    env->GetMethodID(clazz, "onModulationReported", "(I)V"),
+                                    modulationType);
             }
             break;
         }
-        case FrontendScanMessageTypeExt1_1::HIGH_PRIORITY: {
-            bool isHighPriority = message.isHighPriority();
+        case FrontendScanMessageType::HIGH_PRIORITY: {
+            bool isHighPriority = message.get<FrontendScanMessage::Tag::isHighPriority>();
             env->CallVoidMethod(
                     frontend,
                     env->GetMethodID(clazz, "onPriorityReported", "(Z)V"),
                     isHighPriority);
             break;
         }
-        case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: {
-            jint dvbcAnnex = (jint) message.annex();
+        case FrontendScanMessageType::DVBC_ANNEX: {
+            jint dvbcAnnex = (jint)message.get<FrontendScanMessage::Tag::annex>();
             env->CallVoidMethod(
                     frontend,
                     env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
@@ -1153,57 +1170,57 @@
 
 FrontendClientCallbackImpl::~FrontendClientCallbackImpl() {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (mObject != NULL) {
+    if (mObject != nullptr) {
         env->DeleteWeakGlobalRef(mObject);
-        mObject = NULL;
+        mObject = nullptr;
     }
 }
 
 /////////////// Tuner ///////////////////////
-
 sp<TunerClient> JTuner::mTunerClient;
 
-JTuner::JTuner(JNIEnv *env, jobject thiz)
-    : mClass(NULL) {
+JTuner::JTuner(JNIEnv *env, jobject thiz) : mClass(nullptr) {
     jclass clazz = env->GetObjectClass(thiz);
-    CHECK(clazz != NULL);
+    CHECK(clazz != nullptr);
 
     mClass = (jclass)env->NewGlobalRef(clazz);
     mObject = env->NewWeakGlobalRef(thiz);
-    if (mTunerClient == NULL) {
+    if (mTunerClient == nullptr) {
         mTunerClient = new TunerClient();
     }
+
+    mSharedFeId = (int)Constant::INVALID_FRONTEND_ID;
 }
 
 JTuner::~JTuner() {
-    if (mFeClient != NULL) {
+    if (mFeClient != nullptr) {
         mFeClient->close();
     }
-    if (mDemuxClient != NULL) {
+    if (mDemuxClient != nullptr) {
         mDemuxClient->close();
     }
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
     env->DeleteWeakGlobalRef(mObject);
     env->DeleteGlobalRef(mClass);
-    mTunerClient = NULL;
-    mFeClient = NULL;
-    mDemuxClient = NULL;
-    mClass = NULL;
-    mObject = NULL;
+    mTunerClient = nullptr;
+    mFeClient = nullptr;
+    mDemuxClient = nullptr;
+    mClass = nullptr;
+    mObject = nullptr;
 }
 
 jint JTuner::getTunerVersion() {
-    ALOGD("JTuner::getTunerVersion()");
-    return (jint) mTunerClient->getHalTunerVersion();
+    ALOGV("JTuner::getTunerVersion()");
+    return (jint)mTunerClient->getHalTunerVersion();
 }
 
 jobject JTuner::getFrontendIds() {
-    ALOGD("JTuner::getFrontendIds()");
-    vector<FrontendId> ids = mTunerClient->getFrontendIds();
+    ALOGV("JTuner::getFrontendIds()");
+    vector<int32_t> ids = mTunerClient->getFrontendIds();
     if (ids.size() == 0) {
         ALOGW("Frontend isn't available");
-        return NULL;
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1214,9 +1231,9 @@
     jclass integerClazz = env->FindClass("java/lang/Integer");
     jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
 
-    for (int i=0; i < ids.size(); i++) {
-       jobject idObj = env->NewObject(integerClazz, intInit, ids[i]);
-       env->CallBooleanMethod(obj, arrayListAdd, idObj);
+    for (int i = 0; i < ids.size(); i++) {
+        jobject idObj = env->NewObject(integerClazz, intInit, ids[i]);
+        env->CallBooleanMethod(obj, arrayListAdd, idObj);
     }
     return obj;
 }
@@ -1224,14 +1241,14 @@
 jobject JTuner::openFrontendByHandle(int feHandle) {
     // TODO: Handle reopening frontend with different handle
     sp<FrontendClient> feClient = mTunerClient->openFrontend(feHandle);
-    if (feClient == NULL) {
+    if (feClient == nullptr) {
         ALOGE("Failed to open frontend");
-        return NULL;
+        return nullptr;
     }
     mFeClient = feClient;
 
     mFeId = mFeClient->getId();
-    if (mDemuxClient != NULL) {
+    if (mDemuxClient != nullptr) {
         mDemuxClient->setFrontendDataSource(mFeClient);
     }
 
@@ -1240,10 +1257,11 @@
     if (env->IsSameObject(tuner, nullptr)) {
         ALOGE("openFrontendByHandle"
                 "Tuner object has been freed. Failed to open frontend.");
-        return NULL;
+        return nullptr;
     }
 
-    sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject);
+    sp<FrontendClientCallbackImpl> feClientCb =
+            new FrontendClientCallbackImpl(env->NewWeakGlobalRef(mObject));
     mFeClient->setCallback(feClientCb);
     // TODO: add more fields to frontend
     return env->NewObject(
@@ -1253,127 +1271,135 @@
             (jint) mFeId);
 }
 
-jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+int JTuner::shareFrontend(int feId) {
+    if (mFeClient != nullptr) {
+        ALOGE("Cannot share frontend:%d because this session is already holding %d",
+              feId, mFeClient->getId());
+        return (int)Result::INVALID_STATE;
+    }
+
+    mSharedFeId = feId;
+    return (int)Result::SUCCESS;
+}
+
+jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
 
-    jint typeCap = caps.analogCaps().typeCap;
-    jint sifStandardCap = caps.analogCaps().sifStandardCap;
+    jint typeCap = caps.get<FrontendCapabilities::Tag::analogCaps>().typeCap;
+    jint sifStandardCap = caps.get<FrontendCapabilities::Tag::analogCaps>().sifStandardCap;
     return env->NewObject(clazz, capsInit, typeCap, sifStandardCap);
 }
 
-jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V");
 
-    jint bandwidthCap = caps.atsc3Caps().bandwidthCap;
-    jint modulationCap = caps.atsc3Caps().modulationCap;
-    jint timeInterleaveModeCap = caps.atsc3Caps().timeInterleaveModeCap;
-    jint codeRateCap = caps.atsc3Caps().codeRateCap;
-    jint fecCap = caps.atsc3Caps().fecCap;
-    jint demodOutputFormatCap = caps.atsc3Caps().demodOutputFormatCap;
+    jint bandwidthCap = caps.get<FrontendCapabilities::Tag::atsc3Caps>().bandwidthCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::atsc3Caps>().modulationCap;
+    jint timeInterleaveModeCap =
+            caps.get<FrontendCapabilities::Tag::atsc3Caps>().timeInterleaveModeCap;
+    jint codeRateCap = caps.get<FrontendCapabilities::Tag::atsc3Caps>().codeRateCap;
+    jint fecCap = caps.get<FrontendCapabilities::Tag::atsc3Caps>().fecCap;
+    jint demodOutputFormatCap =
+            caps.get<FrontendCapabilities::Tag::atsc3Caps>().demodOutputFormatCap;
 
     return env->NewObject(clazz, capsInit, bandwidthCap, modulationCap, timeInterleaveModeCap,
             codeRateCap, fecCap, demodOutputFormatCap);
 }
 
-jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(I)V");
 
-    jint modulationCap = caps.atscCaps().modulationCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::atscCaps>().modulationCap;
 
     return env->NewObject(clazz, capsInit, modulationCap);
 }
 
-jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V");
 
-    jint modulationCap = caps.dvbcCaps().modulationCap;
-    jlong fecCap = caps.dvbcCaps().fecCap;
-    jint annexCap = caps.dvbcCaps().annexCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::dvbcCaps>().modulationCap;
+    jlong fecCap = caps.get<FrontendCapabilities::Tag::dvbcCaps>().fecCap;
+    jint annexCap = caps.get<FrontendCapabilities::Tag::dvbcCaps>().annexCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap);
 }
 
-jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V");
 
-    jint modulationCap = caps.dvbsCaps().modulationCap;
-    jlong innerfecCap = caps.dvbsCaps().innerfecCap;
-    jint standard = caps.dvbsCaps().standard;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::dvbsCaps>().modulationCap;
+    jlong innerfecCap = caps.get<FrontendCapabilities::Tag::dvbsCaps>().innerfecCap;
+    jint standard = caps.get<FrontendCapabilities::Tag::dvbsCaps>().standard;
 
     return env->NewObject(clazz, capsInit, modulationCap, innerfecCap, standard);
 }
 
-jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIZZ)V");
 
-    jint transmissionModeCap = caps.dvbtCaps().transmissionModeCap;
-    jint bandwidthCap = caps.dvbtCaps().bandwidthCap;
-    jint constellationCap = caps.dvbtCaps().constellationCap;
-    jint coderateCap = caps.dvbtCaps().coderateCap;
-    jint hierarchyCap = caps.dvbtCaps().hierarchyCap;
-    jint guardIntervalCap = caps.dvbtCaps().guardIntervalCap;
-    jboolean isT2Supported = caps.dvbtCaps().isT2Supported;
-    jboolean isMisoSupported = caps.dvbtCaps().isMisoSupported;
+    jint transmissionModeCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().transmissionModeCap;
+    jint bandwidthCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().bandwidthCap;
+    jint constellationCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().constellationCap;
+    jint coderateCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().coderateCap;
+    jint hierarchyCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().hierarchyCap;
+    jint guardIntervalCap = caps.get<FrontendCapabilities::Tag::dvbtCaps>().guardIntervalCap;
+    jboolean isT2Supported = caps.get<FrontendCapabilities::Tag::dvbtCaps>().isT2Supported;
+    jboolean isMisoSupported = caps.get<FrontendCapabilities::Tag::dvbtCaps>().isMisoSupported;
 
     return env->NewObject(clazz, capsInit, transmissionModeCap, bandwidthCap, constellationCap,
             coderateCap, hierarchyCap, guardIntervalCap, isT2Supported, isMisoSupported);
 }
 
-jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
 
-    jint modulationCap = caps.isdbs3Caps().modulationCap;
-    jint coderateCap = caps.isdbs3Caps().coderateCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::isdbs3Caps>().modulationCap;
+    jint coderateCap = caps.get<FrontendCapabilities::Tag::isdbs3Caps>().coderateCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, coderateCap);
 }
 
-jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V");
 
-    jint modulationCap = caps.isdbsCaps().modulationCap;
-    jint coderateCap = caps.isdbsCaps().coderateCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::isdbsCaps>().modulationCap;
+    jint coderateCap = caps.get<FrontendCapabilities::Tag::isdbsCaps>().coderateCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, coderateCap);
 }
 
-jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
+jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIII)V");
 
-    jint modeCap = caps.isdbtCaps().modeCap;
-    jint bandwidthCap = caps.isdbtCaps().bandwidthCap;
-    jint modulationCap = caps.isdbtCaps().modulationCap;
-    jint coderateCap = caps.isdbtCaps().coderateCap;
-    jint guardIntervalCap = caps.isdbtCaps().guardIntervalCap;
+    jint modeCap = caps.get<FrontendCapabilities::Tag::isdbtCaps>().modeCap;
+    jint bandwidthCap = caps.get<FrontendCapabilities::Tag::isdbtCaps>().bandwidthCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::isdbtCaps>().modulationCap;
+    jint coderateCap = caps.get<FrontendCapabilities::Tag::isdbtCaps>().coderateCap;
+    jint guardIntervalCap = caps.get<FrontendCapabilities::Tag::isdbtCaps>().guardIntervalCap;
 
     return env->NewObject(clazz, capsInit, modeCap, bandwidthCap, modulationCap, coderateCap,
             guardIntervalCap);
 }
 
-jobject JTuner::getDtmbFrontendCaps(JNIEnv *env, int id) {
+jobject JTuner::getDtmbFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DtmbFrontendCapabilities");
     jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V");
 
-    shared_ptr<FrontendDtmbCapabilities> dtmbCaps = mTunerClient->getFrontendDtmbCapabilities(id);
-    if (dtmbCaps == NULL) {
-        return NULL;
-    }
-
-    jint modulationCap = dtmbCaps->modulationCap;
-    jint transmissionModeCap = dtmbCaps->transmissionModeCap;
-    jint guardIntervalCap = dtmbCaps->guardIntervalCap;
-    jint interleaveModeCap = dtmbCaps->interleaveModeCap;
-    jint codeRateCap = dtmbCaps->codeRateCap;
-    jint bandwidthCap = dtmbCaps->bandwidthCap;
+    jint modulationCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().modulationCap;
+    jint transmissionModeCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().transmissionModeCap;
+    jint guardIntervalCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().guardIntervalCap;
+    jint interleaveModeCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().interleaveModeCap;
+    jint codeRateCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().codeRateCap;
+    jint bandwidthCap = caps.get<FrontendCapabilities::Tag::dtmbCaps>().bandwidthCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, transmissionModeCap, guardIntervalCap,
             interleaveModeCap, codeRateCap, bandwidthCap);
@@ -1382,8 +1408,8 @@
 jobject JTuner::getFrontendInfo(int id) {
     shared_ptr<FrontendInfo> feInfo;
     feInfo = mTunerClient->getFrontendInfo(id);
-    if (feInfo == NULL) {
-        return NULL;
+    if (feInfo == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1402,70 +1428,60 @@
     env->SetIntArrayRegion(
             statusCaps, 0, feInfo->statusCaps.size(),
             reinterpret_cast<jint*>(&feInfo->statusCaps[0]));
-    FrontendInfo::FrontendCapabilities caps = feInfo->frontendCaps;
+    FrontendCapabilities caps = feInfo->frontendCaps;
 
-    jobject jcaps = NULL;
-
-    if (feInfo->type == static_cast<FrontendType>(
-            ::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
-        jcaps = getDtmbFrontendCaps(env, id);
-    }
-
+    jobject jcaps = nullptr;
     switch(feInfo->type) {
         case FrontendType::ANALOG:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::analogCaps == caps.getTag()) {
                 jcaps = getAnalogFrontendCaps(env, caps);
             }
             break;
         case FrontendType::ATSC3:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::atsc3Caps == caps.getTag()) {
                 jcaps = getAtsc3FrontendCaps(env, caps);
             }
             break;
         case FrontendType::ATSC:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::atscCaps == caps.getTag()) {
                 jcaps = getAtscFrontendCaps(env, caps);
             }
             break;
         case FrontendType::DVBC:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::dvbcCaps == caps.getTag()) {
                 jcaps = getDvbcFrontendCaps(env, caps);
             }
             break;
         case FrontendType::DVBS:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::dvbsCaps == caps.getTag()) {
                 jcaps = getDvbsFrontendCaps(env, caps);
             }
             break;
         case FrontendType::DVBT:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::dvbtCaps == caps.getTag()) {
                 jcaps = getDvbtFrontendCaps(env, caps);
             }
             break;
         case FrontendType::ISDBS:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::isdbsCaps == caps.getTag()) {
                 jcaps = getIsdbsFrontendCaps(env, caps);
             }
             break;
         case FrontendType::ISDBS3:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::isdbs3Caps == caps.getTag()) {
                 jcaps = getIsdbs3FrontendCaps(env, caps);
             }
             break;
         case FrontendType::ISDBT:
-            if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps
-                    == caps.getDiscriminator()) {
+            if (FrontendCapabilities::Tag::isdbtCaps == caps.getTag()) {
                 jcaps = getIsdbtFrontendCaps(env, caps);
             }
             break;
+        case FrontendType::DTMB:
+            if (FrontendCapabilities::Tag::dtmbCaps == caps.getTag()) {
+                jcaps = getDtmbFrontendCaps(env, caps);
+            }
+            break;
         default:
             break;
     }
@@ -1476,21 +1492,21 @@
 }
 
 jobject JTuner::openLnbByHandle(int handle) {
-    if (mTunerClient == NULL) {
-        return NULL;
+    if (mTunerClient == nullptr) {
+        return nullptr;
     }
 
     sp<LnbClient> lnbClient;
     sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl();
     lnbClient = mTunerClient->openLnb(handle);
-    if (lnbClient == NULL) {
+    if (lnbClient == nullptr) {
         ALOGD("Failed to open lnb, handle = %d", handle);
-        return NULL;
+        return nullptr;
     }
 
     if (lnbClient->setCallback(callback) != Result::SUCCESS) {
         ALOGD("Failed to set lnb callback");
-        return NULL;
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1506,8 +1522,8 @@
 }
 
 jobject JTuner::openLnbByName(jstring name) {
-    if (mTunerClient == NULL) {
-        return NULL;
+    if (mTunerClient == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1515,14 +1531,14 @@
     sp<LnbClient> lnbClient;
     sp<LnbClientCallbackImpl> callback = new LnbClientCallbackImpl();
     lnbClient = mTunerClient->openLnbByName(lnbName);
-    if (lnbClient == NULL) {
+    if (lnbClient == nullptr) {
         ALOGD("Failed to open lnb by name, name = %s", lnbName.c_str());
-        return NULL;
+        return nullptr;
     }
 
     if (lnbClient->setCallback(callback) != Result::SUCCESS) {
         ALOGD("Failed to set lnb callback");
-        return NULL;
+        return nullptr;
     }
 
     jobject lnbObj = env->NewObject(
@@ -1536,12 +1552,12 @@
     return lnbObj;
 }
 
-int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) {
+int JTuner::tune(const FrontendSettings &settings) {
     if (mFeClient == nullptr) {
         ALOGE("frontend is not initialized");
         return (int)Result::INVALID_STATE;
     }
-    return (int) mFeClient->tune(settings, settingsExt1_1);
+    return (int)mFeClient->tune(settings);
 }
 
 int JTuner::stopTune() {
@@ -1552,18 +1568,17 @@
     return (int) mFeClient->stopTune();
 }
 
-int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    if (mFeClient == NULL) {
+int JTuner::scan(const FrontendSettings &settings, FrontendScanType scanType) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
-    Result result = mFeClient->scan(settings, scanType, settingsExt1_1);
+    Result result = mFeClient->scan(settings, scanType);
     return (int)result;
 }
 
 int JTuner::stopScan() {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
@@ -1572,11 +1587,11 @@
 }
 
 int JTuner::setLnb(sp<LnbClient> lnbClient) {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
-    if (lnbClient == NULL) {
+    if (lnbClient == nullptr) {
         ALOGE("lnb is not initialized");
         return (int)Result::INVALID_STATE;
     }
@@ -1585,7 +1600,7 @@
 }
 
 int JTuner::setLna(bool enable) {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
@@ -1600,12 +1615,14 @@
 
     if (mDemuxClient == nullptr) {
         mDemuxClient = mTunerClient->openDemux(handle);
-        if (mDemuxClient == NULL) {
+        if (mDemuxClient == nullptr) {
             ALOGE("Failed to open demux");
             return Result::UNKNOWN_ERROR;
         }
-        if (mFeClient != NULL) {
-            mDemuxClient->setFrontendDataSource(mFeClient);
+        if (mFeClient != nullptr) {
+            return mDemuxClient->setFrontendDataSource(mFeClient);
+        } else if (mSharedFeId != (int)Constant::INVALID_FRONTEND_ID) {
+            return mDemuxClient->setFrontendDataSourceById(mSharedFeId);
         }
     }
 
@@ -1615,26 +1632,28 @@
 jint JTuner::close() {
     Result res = Result::SUCCESS;
 
-    if (mFeClient != NULL) {
+    if (mFeClient != nullptr) {
         res = mFeClient->close();
         if (res != Result::SUCCESS) {
-            return (jint) res;
+            return (jint)res;
         }
-        mFeClient = NULL;
+        mFeClient = nullptr;
     }
-    if (mDemuxClient != NULL) {
+    if (mDemuxClient != nullptr) {
         res = mDemuxClient->close();
         if (res != Result::SUCCESS) {
-            return (jint) res;
+            return (jint)res;
         }
-        mDemuxClient = NULL;
+        mDemuxClient = nullptr;
     }
-    return (jint) res;
+
+    mSharedFeId = (int)Constant::INVALID_FRONTEND_ID;
+    return (jint)res;
 }
 
 jobject JTuner::getAvSyncHwId(sp<FilterClient> filterClient) {
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
 
     int avSyncHwId = mDemuxClient->getAvSyncHwId(filterClient);
@@ -1644,12 +1663,12 @@
         jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
         return env->NewObject(integerClazz, intInit, avSyncHwId);
     }
-    return NULL;
+    return nullptr;
 }
 
 jobject JTuner::getAvSyncTime(jint id) {
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
     long time = mDemuxClient->getAvSyncTime((int)id);
     if (time >= 0) {
@@ -1658,19 +1677,18 @@
         jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
         return env->NewObject(longClazz, longInit, static_cast<jlong>(time));
     }
-    return NULL;
+    return nullptr;
 }
 
 int JTuner::connectCiCam(jint id) {
-    if (mDemuxClient == NULL) {
+    if (mDemuxClient == nullptr) {
         return (int)Result::NOT_INITIALIZED;
     }
-    Result r = mDemuxClient->connectCiCam((int)id);
-    return (int) r;
+    return (int)mDemuxClient->connectCiCam((int)id);
 }
 
 int JTuner::linkCiCam(int id) {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Constant::INVALID_LTS_ID;
     }
@@ -1678,35 +1696,30 @@
 }
 
 int JTuner::disconnectCiCam() {
-    if (mDemuxClient == NULL) {
+    if (mDemuxClient == nullptr) {
         return (int)Result::NOT_INITIALIZED;
     }
-    Result r = mDemuxClient->disconnectCiCam();
-    return (int) r;
+    return (int)mDemuxClient->disconnectCiCam();
 }
 
-
 int JTuner::unlinkCiCam(int id) {
-    if (mFeClient == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend client is not initialized");
         return (int)Result::INVALID_STATE;
     }
-
-    Result r = mFeClient->unlinkCiCamToFrontend(id);
-
-    return (int) r;
+    return (int)mFeClient->unlinkCiCamToFrontend(id);
 }
 
 jobject JTuner::openDescrambler() {
-    ALOGD("JTuner::openDescrambler");
+    ALOGV("JTuner::openDescrambler");
     if (mTunerClient == nullptr || mDemuxClient == nullptr) {
-        return NULL;
+        return nullptr;
     }
     sp<DescramblerClient> descramblerClient = mTunerClient->openDescrambler(0/*unused*/);
 
-    if (descramblerClient == NULL) {
+    if (descramblerClient == nullptr) {
         ALOGD("Failed to open descrambler");
-        return NULL;
+        return nullptr;
     }
 
     descramblerClient->setDemuxSource(mDemuxClient);
@@ -1724,31 +1737,28 @@
 }
 
 jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
 
     sp<FilterClient> filterClient;
     sp<FilterClientCallbackImpl> callback = new FilterClientCallbackImpl();
     filterClient = mDemuxClient->openFilter(type, bufferSize, callback);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to open filter, type = %d", type.mainType);
-        return NULL;
+        return nullptr;
     }
-    uint64_t fId;
+    int64_t fId;
     Result res = filterClient->getId64Bit(fId);
     if (res != Result::SUCCESS) {
-        uint32_t id;
+        int32_t id;
         filterClient->getId(id);
-        fId = static_cast<uint64_t>(id);
+        fId = static_cast<int64_t>(id);
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jobject filterObj =
-            env->NewObject(
-                    env->FindClass("android/media/tv/tuner/filter/Filter"),
-                    gFields.filterInitID,
-                    (jlong) fId);
+    jobject filterObj = env->NewObject(env->FindClass("android/media/tv/tuner/filter/Filter"),
+                                       gFields.filterInitID, (jlong)fId);
 
     filterClient->incStrong(filterObj);
     env->SetLongField(filterObj, gFields.filterContext, (jlong)filterClient.get());
@@ -1758,8 +1768,8 @@
 }
 
 jobject JTuner::openTimeFilter() {
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1768,9 +1778,9 @@
                     env->FindClass("android/media/tv/tuner/filter/TimeFilter"),
                     gFields.timeFilterInitID);
     sp<TimeFilterClient> timeFilterClient = mDemuxClient->openTimeFilter();
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed to open time filter.");
-        return NULL;
+        return nullptr;
     }
     timeFilterClient->incStrong(timeFilterObj);
     env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterClient.get());
@@ -1780,15 +1790,15 @@
 
 jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
     ALOGD("JTuner::openDvr");
-    if (mDemuxClient == NULL) {
-        return NULL;
+    if (mDemuxClient == nullptr) {
+        return nullptr;
     }
     sp<DvrClient> dvrClient;
     sp<DvrClientCallbackImpl> callback = new DvrClientCallbackImpl();
     dvrClient = mDemuxClient->openDvr(type, (int) bufferSize, callback);
 
-    if (dvrClient == NULL) {
-        return NULL;
+    if (dvrClient == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1815,14 +1825,14 @@
 }
 
 jobject JTuner::getDemuxCaps() {
-    if (mTunerClient == NULL) {
-        return NULL;
+    if (mTunerClient == nullptr) {
+        return nullptr;
     }
 
     shared_ptr<DemuxCapabilities> caps;
     caps = mTunerClient->getDemuxCaps();
-    if (caps == NULL) {
-        return NULL;
+    if (caps == nullptr) {
+        return nullptr;
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1852,25 +1862,19 @@
 }
 
 jobject JTuner::getFrontendStatus(jintArray types) {
-    if (mFeClient == NULL) {
-        return NULL;
+    if (mFeClient == nullptr) {
+        return nullptr;
     }
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jsize size = env->GetArrayLength(types);
     jint intTypes[size];
     env->GetIntArrayRegion(types, 0, size, intTypes);
     std::vector<FrontendStatusType> v;
-    std::vector<FrontendStatusTypeExt1_1> v_1_1;
     for (int i = 0; i < size; i++) {
-        if (isV1_1ExtendedStatusType(intTypes[i])) {
-            v_1_1.push_back(static_cast<FrontendStatusTypeExt1_1>(intTypes[i]));
-        } else {
-            v.push_back(static_cast<FrontendStatusType>(intTypes[i]));
-        }
+        v.push_back(static_cast<FrontendStatusType>(intTypes[i]));
     }
 
-    hidl_vec<FrontendStatus> status = mFeClient->getStatus(v);
-    hidl_vec<FrontendStatusExt1_1> status_1_1 = mFeClient->getStatusExtended_1_1(v_1_1);
+    vector<FrontendStatus> status = mFeClient->getStatus(v);
 
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendStatus");
     jmethodID init = env->GetMethodID(clazz, "<init>", "()V");
@@ -1882,96 +1886,114 @@
     jmethodID initBoolean = env->GetMethodID(booleanClazz, "<init>", "(Z)V");
 
     for (auto s : status) {
-        switch(s.getDiscriminator()) {
-            case FrontendStatus::hidl_discriminator::isDemodLocked: {
+        switch (s.getTag()) {
+            case FrontendStatus::Tag::isDemodLocked: {
                 jfieldID field = env->GetFieldID(clazz, "mIsDemodLocked", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isDemodLocked()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(
+                                               s.get<FrontendStatus::Tag::isDemodLocked>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::snr: {
+            case FrontendStatus::Tag::snr: {
                 jfieldID field = env->GetFieldID(clazz, "mSnr", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.snr()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::snr>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::ber: {
+            case FrontendStatus::Tag::ber: {
                 jfieldID field = env->GetFieldID(clazz, "mBer", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.ber()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::ber>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::per: {
+            case FrontendStatus::Tag::per: {
                 jfieldID field = env->GetFieldID(clazz, "mPer", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.per()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::per>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::preBer: {
+            case FrontendStatus::Tag::preBer: {
                 jfieldID field = env->GetFieldID(clazz, "mPerBer", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.preBer()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::preBer>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::signalQuality: {
+            case FrontendStatus::Tag::signalQuality: {
                 jfieldID field = env->GetFieldID(clazz, "mSignalQuality", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.signalQuality()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(
+                                               s.get<FrontendStatus::Tag::signalQuality>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::signalStrength: {
+            case FrontendStatus::Tag::signalStrength: {
                 jfieldID field = env->GetFieldID(clazz, "mSignalStrength", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.signalStrength()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(
+                                               s.get<FrontendStatus::Tag::signalStrength>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::symbolRate: {
+            case FrontendStatus::Tag::symbolRate: {
                 jfieldID field = env->GetFieldID(clazz, "mSymbolRate", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.symbolRate()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::symbolRate>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::innerFec: {
+            case FrontendStatus::Tag::innerFec: {
                 jfieldID field = env->GetFieldID(clazz, "mInnerFec", "Ljava/lang/Long;");
                 jclass longClazz = env->FindClass("java/lang/Long");
                 jmethodID initLong = env->GetMethodID(longClazz, "<init>", "(J)V");
-                jobject newLongObj = env->NewObject(
-                        longClazz, initLong, static_cast<jlong>(s.innerFec()));
+                jobject newLongObj =
+                        env->NewObject(longClazz, initLong,
+                                       static_cast<jlong>(s.get<FrontendStatus::Tag::innerFec>()));
                 env->SetObjectField(statusObj, field, newLongObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::modulation: {
+            case FrontendStatus::Tag::modulationStatus: {
                 jfieldID field = env->GetFieldID(clazz, "mModulation", "Ljava/lang/Integer;");
-                FrontendModulationStatus modulation = s.modulation();
+                FrontendModulationStatus modulation =
+                        s.get<FrontendStatus::Tag::modulationStatus>();
                 jint intModulation;
                 bool valid = true;
-                switch(modulation.getDiscriminator()) {
-                    case FrontendModulationStatus::hidl_discriminator::dvbc: {
-                        intModulation = static_cast<jint>(modulation.dvbc());
+                switch (modulation.getTag()) {
+                    case FrontendModulationStatus::Tag::dvbc: {
+                        intModulation = static_cast<jint>(
+                                modulation.get<FrontendModulationStatus::Tag::dvbc>());
                         break;
                     }
-                    case FrontendModulationStatus::hidl_discriminator::dvbs: {
-                        intModulation = static_cast<jint>(modulation.dvbs());
+                    case FrontendModulationStatus::Tag::dvbs: {
+                        intModulation = static_cast<jint>(
+                                modulation.get<FrontendModulationStatus::Tag::dvbs>());
                         break;
                     }
-                    case FrontendModulationStatus::hidl_discriminator::isdbs: {
-                        intModulation = static_cast<jint>(modulation.isdbs());
+                    case FrontendModulationStatus::Tag::isdbs: {
+                        intModulation = static_cast<jint>(
+                                modulation.get<FrontendModulationStatus::Tag::isdbs>());
                         break;
                     }
-                    case FrontendModulationStatus::hidl_discriminator::isdbs3: {
-                        intModulation = static_cast<jint>(modulation.isdbs3());
+                    case FrontendModulationStatus::Tag::isdbs3: {
+                        intModulation = static_cast<jint>(
+                                modulation.get<FrontendModulationStatus::Tag::isdbs3>());
                         break;
                     }
-                    case FrontendModulationStatus::hidl_discriminator::isdbt: {
-                        intModulation = static_cast<jint>(modulation.isdbt());
+                    case FrontendModulationStatus::Tag::isdbt: {
+                        intModulation = static_cast<jint>(
+                                modulation.get<FrontendModulationStatus::Tag::isdbt>());
                         break;
                     }
                     default: {
@@ -1985,51 +2007,58 @@
                 }
                 break;
             }
-            case FrontendStatus::hidl_discriminator::inversion: {
+            case FrontendStatus::Tag::inversion: {
                 jfieldID field = env->GetFieldID(clazz, "mInversion", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.inversion()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::inversion>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::lnbVoltage: {
+            case FrontendStatus::Tag::lnbVoltage: {
                 jfieldID field = env->GetFieldID(clazz, "mLnbVoltage", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.lnbVoltage()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::lnbVoltage>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::plpId: {
+            case FrontendStatus::Tag::plpId: {
                 jfieldID field = env->GetFieldID(clazz, "mPlpId", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.plpId()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::plpId>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::isEWBS: {
+            case FrontendStatus::Tag::isEWBS: {
                 jfieldID field = env->GetFieldID(clazz, "mIsEwbs", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isEWBS()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(s.get<FrontendStatus::Tag::isEWBS>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::agc: {
+            case FrontendStatus::Tag::agc: {
                 jfieldID field = env->GetFieldID(clazz, "mAgc", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.agc()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::agc>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::isLnaOn: {
+            case FrontendStatus::Tag::isLnaOn: {
                 jfieldID field = env->GetFieldID(clazz, "mIsLnaOn", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isLnaOn()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(
+                                               s.get<FrontendStatus::Tag::isLnaOn>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::isLayerError: {
+            case FrontendStatus::Tag::isLayerError: {
                 jfieldID field = env->GetFieldID(clazz, "mIsLayerErrors", "[Z");
-                hidl_vec<bool> layerErr = s.isLayerError();
+                vector<bool> layerErr = s.get<FrontendStatus::Tag::isLayerError>();
 
                 jbooleanArray valObj = env->NewBooleanArray(layerErr.size());
 
@@ -2040,44 +2069,48 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::mer: {
+            case FrontendStatus::Tag::mer: {
                 jfieldID field = env->GetFieldID(clazz, "mMer", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.mer()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::mer>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::freqOffset: {
+            case FrontendStatus::Tag::freqOffset: {
                 jfieldID field = env->GetFieldID(clazz, "mFreqOffset", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.freqOffset()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::freqOffset>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::hierarchy: {
+            case FrontendStatus::Tag::hierarchy: {
                 jfieldID field = env->GetFieldID(clazz, "mHierarchy", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.hierarchy()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::hierarchy>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::isRfLocked: {
+            case FrontendStatus::Tag::isRfLocked: {
                 jfieldID field = env->GetFieldID(clazz, "mIsRfLocked", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isRfLocked()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(
+                                               s.get<FrontendStatus::Tag::isRfLocked>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatus::hidl_discriminator::plpInfo: {
+            case FrontendStatus::Tag::plpInfo: {
                 jfieldID field = env->GetFieldID(clazz, "mPlpInfo",
                         "[Landroid/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo;");
                 jclass plpClazz = env->FindClass(
                         "android/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo");
                 jmethodID initPlp = env->GetMethodID(plpClazz, "<init>", "(IZI)V");
 
-                hidl_vec<FrontendStatusAtsc3PlpInfo> plpInfos = s.plpInfo();
-
-                jobjectArray valObj = env->NewObjectArray(plpInfos.size(), plpClazz, NULL);
+                vector<FrontendStatusAtsc3PlpInfo> plpInfos = s.get<FrontendStatus::Tag::plpInfo>();
+                jobjectArray valObj = env->NewObjectArray(plpInfos.size(), plpClazz, nullptr);
                 for (int i = 0; i < plpInfos.size(); i++) {
                     auto info = plpInfos[i];
                     jint plpId = (jint) info.plpId;
@@ -2091,74 +2124,75 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            default: {
-                break;
-            }
-        }
-    }
-
-    for (auto s : status_1_1) {
-        switch(s.getDiscriminator()) {
-            case FrontendStatusExt1_1::hidl_discriminator::modulations: {
+            case FrontendStatus::Tag::modulations: {
                 jfieldID field = env->GetFieldID(clazz, "mModulationsExt", "[I");
-                std::vector<FrontendModulation> v = s.modulations();
+                std::vector<FrontendModulation> v = s.get<FrontendStatus::Tag::modulations>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 bool valid = false;
                 jint m[1];
                 for (int i = 0; i < v.size(); i++) {
                     auto modulation = v[i];
-                    switch(modulation.getDiscriminator()) {
-                        case FrontendModulation::hidl_discriminator::dvbc: {
-                            m[0] = static_cast<jint>(modulation.dvbc());
+                    switch (modulation.getTag()) {
+                        case FrontendModulation::Tag::dvbc: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::dvbc>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::dvbs: {
-                            m[0] = static_cast<jint>(modulation.dvbs());
+                        case FrontendModulation::Tag::dvbs: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::dvbs>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                            break;
                         }
-                        case FrontendModulation::hidl_discriminator::dvbt: {
-                            m[0] = static_cast<jint>(modulation.dvbt());
+                        case FrontendModulation::Tag::dvbt: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::dvbt>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::isdbs: {
-                            m[0] = static_cast<jint>(modulation.isdbs());
+                        case FrontendModulation::Tag::isdbs: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::isdbs>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::isdbs3: {
-                            m[0] = static_cast<jint>(modulation.isdbs3());
+                        case FrontendModulation::Tag::isdbs3: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::isdbs3>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::isdbt: {
-                            m[0] = static_cast<jint>(modulation.isdbt());
+                        case FrontendModulation::Tag::isdbt: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::isdbt>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::atsc: {
-                            m[0] = static_cast<jint>(modulation.atsc());
+                        case FrontendModulation::Tag::atsc: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::atsc>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::atsc3: {
-                            m[0] = static_cast<jint>(modulation.atsc3());
+                        case FrontendModulation::Tag::atsc3: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::atsc3>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
                         }
-                        case FrontendModulation::hidl_discriminator::dtmb: {
-                            m[0] = static_cast<jint>(modulation.dtmb());
+                        case FrontendModulation::Tag::dtmb: {
+                            m[0] = static_cast<jint>(
+                                    modulation.get<FrontendModulation::Tag::dtmb>());
                             env->SetIntArrayRegion(valObj, i, 1, m);
                             valid = true;
                             break;
@@ -2172,9 +2206,9 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::bers: {
+            case FrontendStatus::Tag::bers: {
                 jfieldID field = env->GetFieldID(clazz, "mBers", "[I");
-                std::vector<uint32_t> v = s.bers();
+                std::vector<int32_t> v = s.get<FrontendStatus::Tag::bers>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
@@ -2182,10 +2216,9 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::codeRates: {
+            case FrontendStatus::Tag::codeRates: {
                 jfieldID field = env->GetFieldID(clazz, "mCodeRates", "[I");
-                std::vector<::android::hardware::tv::tuner::V1_1::FrontendInnerFec> v
-                        = s.codeRates();
+                std::vector<FrontendInnerFec> v = s.get<FrontendStatus::Tag::codeRates>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
@@ -2193,30 +2226,35 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::bandwidth: {
+            case FrontendStatus::Tag::bandwidth: {
                 jfieldID field = env->GetFieldID(clazz, "mBandwidth", "Ljava/lang/Integer;");
-                auto bandwidth = s.bandwidth();
+                auto bandwidth = s.get<FrontendStatus::Tag::bandwidth>();
                 jint intBandwidth;
                 bool valid = true;
-                switch(bandwidth.getDiscriminator()) {
-                    case FrontendBandwidth::hidl_discriminator::atsc3: {
-                        intBandwidth = static_cast<jint>(bandwidth.atsc3());
+                switch (bandwidth.getTag()) {
+                    case FrontendBandwidth::Tag::atsc3: {
+                        intBandwidth =
+                                static_cast<jint>(bandwidth.get<FrontendBandwidth::Tag::atsc3>());
                         break;
                     }
-                    case FrontendBandwidth::hidl_discriminator::dvbt: {
-                        intBandwidth = static_cast<jint>(bandwidth.dvbt());
+                    case FrontendBandwidth::Tag::dvbt: {
+                        intBandwidth =
+                                static_cast<jint>(bandwidth.get<FrontendBandwidth::Tag::dvbt>());
                         break;
                     }
-                    case FrontendBandwidth::hidl_discriminator::dvbc: {
-                        intBandwidth = static_cast<jint>(bandwidth.dvbc());
+                    case FrontendBandwidth::Tag::dvbc: {
+                        intBandwidth =
+                                static_cast<jint>(bandwidth.get<FrontendBandwidth::Tag::dvbc>());
                         break;
                     }
-                    case FrontendBandwidth::hidl_discriminator::isdbt: {
-                        intBandwidth = static_cast<jint>(bandwidth.isdbt());
+                    case FrontendBandwidth::Tag::isdbt: {
+                        intBandwidth =
+                                static_cast<jint>(bandwidth.get<FrontendBandwidth::Tag::isdbt>());
                         break;
                     }
-                    case FrontendBandwidth::hidl_discriminator::dtmb: {
-                        intBandwidth = static_cast<jint>(bandwidth.dtmb());
+                    case FrontendBandwidth::Tag::dtmb: {
+                        intBandwidth =
+                                static_cast<jint>(bandwidth.get<FrontendBandwidth::Tag::dtmb>());
                         break;
                     }
                     default:
@@ -2229,22 +2267,25 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::interval: {
+            case FrontendStatus::Tag::interval: {
                 jfieldID field = env->GetFieldID(clazz, "mGuardInterval", "Ljava/lang/Integer;");
-                auto interval = s.interval();
+                auto interval = s.get<FrontendStatus::Tag::interval>();
                 jint intInterval;
                 bool valid = true;
-                switch(interval.getDiscriminator()) {
-                    case FrontendGuardInterval::hidl_discriminator::dvbt: {
-                        intInterval = static_cast<jint>(interval.dvbt());
+                switch (interval.getTag()) {
+                    case FrontendGuardInterval::Tag::dvbt: {
+                        intInterval =
+                                static_cast<jint>(interval.get<FrontendGuardInterval::Tag::dvbt>());
                         break;
                     }
-                    case FrontendGuardInterval::hidl_discriminator::isdbt: {
-                        intInterval = static_cast<jint>(interval.isdbt());
+                    case FrontendGuardInterval::Tag::isdbt: {
+                        intInterval = static_cast<jint>(
+                                interval.get<FrontendGuardInterval::Tag::isdbt>());
                         break;
                     }
-                    case FrontendGuardInterval::hidl_discriminator::dtmb: {
-                        intInterval = static_cast<jint>(interval.dtmb());
+                    case FrontendGuardInterval::Tag::dtmb: {
+                        intInterval =
+                                static_cast<jint>(interval.get<FrontendGuardInterval::Tag::dtmb>());
                         break;
                     }
                     default:
@@ -2257,22 +2298,25 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::transmissionMode: {
+            case FrontendStatus::Tag::transmissionMode: {
                 jfieldID field = env->GetFieldID(clazz, "mTransmissionMode", "Ljava/lang/Integer;");
-                auto transmissionMode = s.transmissionMode();
+                auto transmissionMode = s.get<FrontendStatus::Tag::transmissionMode>();
                 jint intTransmissionMode;
                 bool valid = true;
-                switch(transmissionMode.getDiscriminator()) {
-                    case FrontendTransmissionMode::hidl_discriminator::dvbt: {
-                        intTransmissionMode = static_cast<jint>(transmissionMode.dvbt());
+                switch (transmissionMode.getTag()) {
+                    case FrontendTransmissionMode::Tag::dvbt: {
+                        intTransmissionMode = static_cast<jint>(
+                                transmissionMode.get<FrontendTransmissionMode::Tag::dvbt>());
                         break;
                     }
-                    case FrontendTransmissionMode::hidl_discriminator::isdbt: {
-                        intTransmissionMode = static_cast<jint>(transmissionMode.isdbt());
+                    case FrontendTransmissionMode::Tag::isdbt: {
+                        intTransmissionMode = static_cast<jint>(
+                                transmissionMode.get<FrontendTransmissionMode::Tag::isdbt>());
                         break;
                     }
-                    case FrontendTransmissionMode::hidl_discriminator::dtmb: {
-                        intTransmissionMode = static_cast<jint>(transmissionMode.dtmb());
+                    case FrontendTransmissionMode::Tag::dtmb: {
+                        intTransmissionMode = static_cast<jint>(
+                                transmissionMode.get<FrontendTransmissionMode::Tag::dtmb>());
                         break;
                     }
                     default:
@@ -2285,44 +2329,48 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::uec: {
+            case FrontendStatus::Tag::uec: {
                 jfieldID field = env->GetFieldID(clazz, "mUec", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.uec()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::uec>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::systemId: {
+            case FrontendStatus::Tag::systemId: {
                 jfieldID field = env->GetFieldID(clazz, "mSystemId", "Ljava/lang/Integer;");
-                jobject newIntegerObj = env->NewObject(
-                        intClazz, initInt, static_cast<jint>(s.systemId()));
+                jobject newIntegerObj =
+                        env->NewObject(intClazz, initInt,
+                                       static_cast<jint>(s.get<FrontendStatus::Tag::systemId>()));
                 env->SetObjectField(statusObj, field, newIntegerObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::interleaving: {
+            case FrontendStatus::Tag::interleaving: {
                 jfieldID field = env->GetFieldID(clazz, "mInterleaving", "[I");
-
-                std::vector<FrontendInterleaveMode> v = s.interleaving();
+                std::vector<FrontendInterleaveMode> v = s.get<FrontendStatus::Tag::interleaving>();
                 jintArray valObj = env->NewIntArray(v.size());
                 bool valid = false;
                 jint in[1];
                 for (int i = 0; i < v.size(); i++) {
                     auto interleaving = v[i];
-                    switch(interleaving.getDiscriminator()) {
-                        case FrontendInterleaveMode::hidl_discriminator::atsc3: {
-                            in[0] = static_cast<jint>(interleaving.atsc3());
+                    switch (interleaving.getTag()) {
+                        case FrontendInterleaveMode::Tag::atsc3: {
+                            in[0] = static_cast<jint>(
+                                    interleaving.get<FrontendInterleaveMode::Tag::atsc3>());
                             env->SetIntArrayRegion(valObj, i, 1, in);
                             valid = true;
                             break;
                         }
-                        case FrontendInterleaveMode::hidl_discriminator::dvbc: {
-                            in[0] = static_cast<jint>(interleaving.dvbc());
+                        case FrontendInterleaveMode::Tag::dvbc: {
+                            in[0] = static_cast<jint>(
+                                    interleaving.get<FrontendInterleaveMode::Tag::dvbc>());
                             env->SetIntArrayRegion(valObj, i, 1, in);
                             valid = true;
                            break;
                         }
-                        case FrontendInterleaveMode::hidl_discriminator::dtmb: {
-                            in[0] = static_cast<jint>(interleaving.dtmb());
+                        case FrontendInterleaveMode::Tag::dtmb: {
+                            in[0] = static_cast<jint>(
+                                    interleaving.get<FrontendInterleaveMode::Tag::dtmb>());
                             env->SetIntArrayRegion(valObj, i, 1, in);
                             valid = true;
                            break;
@@ -2336,9 +2384,9 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::isdbtSegment: {
+            case FrontendStatus::Tag::isdbtSegment: {
                 jfieldID field = env->GetFieldID(clazz, "mIsdbtSegment", "[I");
-                std::vector<uint8_t> v = s.isdbtSegment();
+                std::vector<uint8_t> v = s.get<FrontendStatus::Tag::isdbtSegment>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
@@ -2346,9 +2394,9 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::tsDataRate: {
+            case FrontendStatus::Tag::tsDataRate: {
                 jfieldID field = env->GetFieldID(clazz, "mTsDataRate", "[I");
-                std::vector<uint32_t> v = s.tsDataRate();
+                std::vector<int32_t> v = s.get<FrontendStatus::Tag::tsDataRate>();
 
                 jintArray valObj = env->NewIntArray(v.size());
                 env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint*>(&v[0]));
@@ -2356,22 +2404,22 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::rollOff: {
+            case FrontendStatus::Tag::rollOff: {
                 jfieldID field = env->GetFieldID(clazz, "mRollOff", "Ljava/lang/Integer;");
-                auto rollOff = s.rollOff();
+                auto rollOff = s.get<FrontendStatus::Tag::rollOff>();
                 jint intRollOff;
                 bool valid = true;
-                switch(rollOff.getDiscriminator()) {
-                    case FrontendRollOff::hidl_discriminator::dvbs: {
-                        intRollOff = static_cast<jint>(rollOff.dvbs());
+                switch (rollOff.getTag()) {
+                    case FrontendRollOff::Tag::dvbs: {
+                        intRollOff = static_cast<jint>(rollOff.get<FrontendRollOff::Tag::dvbs>());
                         break;
                     }
-                    case FrontendRollOff::hidl_discriminator::isdbs: {
-                        intRollOff = static_cast<jint>(rollOff.isdbs());
+                    case FrontendRollOff::Tag::isdbs: {
+                        intRollOff = static_cast<jint>(rollOff.get<FrontendRollOff::Tag::isdbs>());
                         break;
                     }
-                    case FrontendRollOff::hidl_discriminator::isdbs3: {
-                        intRollOff = static_cast<jint>(rollOff.isdbs3());
+                    case FrontendRollOff::Tag::isdbs3: {
+                        intRollOff = static_cast<jint>(rollOff.get<FrontendRollOff::Tag::isdbs3>());
                         break;
                     }
                     default:
@@ -2384,24 +2432,29 @@
                 }
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::isMiso: {
+            case FrontendStatus::Tag::isMiso: {
                 jfieldID field = env->GetFieldID(clazz, "mIsMisoEnabled", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isMiso()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(s.get<FrontendStatus::Tag::isMiso>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::isLinear: {
+            case FrontendStatus::Tag::isLinear: {
                 jfieldID field = env->GetFieldID(clazz, "mIsLinear", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isLinear()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(
+                                               s.get<FrontendStatus::Tag::isLinear>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
-            case FrontendStatusExt1_1::hidl_discriminator::isShortFrames: {
+            case FrontendStatus::Tag::isShortFrames: {
                 jfieldID field = env->GetFieldID(clazz, "mIsShortFrames", "Ljava/lang/Boolean;");
-                jobject newBooleanObj = env->NewObject(
-                        booleanClazz, initBoolean, static_cast<jboolean>(s.isShortFrames()));
+                jobject newBooleanObj =
+                        env->NewObject(booleanClazz, initBoolean,
+                                       static_cast<jboolean>(
+                                               s.get<FrontendStatus::Tag::isShortFrames>()));
                 env->SetObjectField(statusObj, field, newBooleanObj);
                 break;
             }
@@ -2413,33 +2466,28 @@
     return statusObj;
 }
 
-bool JTuner::isV1_1ExtendedStatusType(int type) {
-    return (type > static_cast<int>(FrontendStatusType::ATSC3_PLP_INFO)
-                && type <= static_cast<int>(FrontendStatusTypeExt1_1::IS_SHORT_FRAMES));
-}
-
 jint JTuner::closeFrontend() {
     Result r = Result::SUCCESS;
 
-    if (mFeClient != NULL) {
+    if (mFeClient != nullptr) {
         r = mFeClient->close();
     }
     if (r == Result::SUCCESS) {
-        mFeClient = NULL;
+        mFeClient = nullptr;
     }
-    return (jint) r;
+    return (jint)r;
 }
 
 jint JTuner::closeDemux() {
     Result r = Result::SUCCESS;
 
-    if (mDemuxClient != NULL) {
+    if (mDemuxClient != nullptr) {
         r = mDemuxClient->close();
     }
     if (r == Result::SUCCESS) {
-        mDemuxClient = NULL;
+        mDemuxClient = nullptr;
     }
-    return (jint) r;
+    return (jint)r;
 }
 }  // namespace android
 
@@ -2450,14 +2498,14 @@
 static sp<JTuner> setTuner(JNIEnv *env, jobject thiz, const sp<JTuner> &tuner) {
     sp<JTuner> old = (JTuner *)env->GetLongField(thiz, gFields.tunerContext);
 
-    if (tuner != NULL) {
+    if (tuner != nullptr) {
         tuner->incStrong(thiz);
     }
-    if (old != NULL) {
+    if (old != nullptr) {
         old->decStrong(thiz);
     }
 
-    if (tuner != NULL) {
+    if (tuner != nullptr) {
         env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get());
     }
 
@@ -2474,25 +2522,25 @@
 
 static DemuxPid getDemuxPid(int pidType, int pid) {
     DemuxPid demuxPid;
-    if ((int)pidType == 1) {
-        demuxPid.tPid(static_cast<DemuxTpid>(pid));
-    } else if ((int)pidType == 2) {
-        demuxPid.mmtpPid(static_cast<DemuxMmtpPid>(pid));
+    if (pidType == 1) {
+        demuxPid.set<DemuxPid::tPid>(pid);
+    } else if (pidType == 2) {
+        demuxPid.set<DemuxPid::mmtpPid>(pid);
     }
     return demuxPid;
 }
 
-static uint32_t getFrontendSettingsFreq(JNIEnv *env, const jobject& settings) {
+static int32_t getFrontendSettingsFreq(JNIEnv *env, const jobject &settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
     jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I");
-    uint32_t freq = static_cast<uint32_t>(env->GetIntField(settings, freqField));
+    int32_t freq = static_cast<int32_t>(env->GetIntField(settings, freqField));
     return freq;
 }
 
-static uint32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject& settings) {
+static int32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject &settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
     jfieldID endFreqField = env->GetFieldID(clazz, "mEndFrequency", "I");
-    uint32_t endFreq = static_cast<uint32_t>(env->GetIntField(settings, endFreqField));
+    int32_t endFreq = static_cast<int32_t>(env->GetIntField(settings, endFreqField));
     return endFreq;
 }
 
@@ -2507,7 +2555,9 @@
 
 static FrontendSettings getAnalogFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings");
     FrontendAnalogType analogType =
             static_cast<FrontendAnalogType>(
@@ -2515,29 +2565,21 @@
     FrontendAnalogSifStandard sifStandard =
             static_cast<FrontendAnalogSifStandard>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mSifStandard", "I")));
-    FrontendAnalogSettings frontendAnalogSettings {
+    FrontendAnalogAftFlag aftFlag = static_cast<FrontendAnalogAftFlag>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mAftFlag", "I")));
+    FrontendAnalogSettings frontendAnalogSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .type = analogType,
             .sifStandard = sifStandard,
+            .aftFlag = aftFlag,
+            .inversion = inversion,
     };
-    frontendSettings.analog(frontendAnalogSettings);
+    frontendSettings.set<FrontendSettings::Tag::analog>(frontendAnalogSettings);
     return frontendSettings;
 }
 
-static void getAnalogFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
-        FrontendSettingsExt1_1& settingsExt1_1) {
-    jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings");
-    FrontendAnalogAftFlag aftFlag =
-            static_cast<FrontendAnalogAftFlag>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mAftFlag", "I")));
-    FrontendAnalogSettingsExt1_1 analogExt1_1 {
-        .aftFlag = aftFlag,
-    };
-    settingsExt1_1.settingExt.analog(analogExt1_1);
-}
-
-static hidl_vec<FrontendAtsc3PlpSettings> getAtsc3PlpSettings(
-        JNIEnv *env, const jobject& settings) {
+static vector<FrontendAtsc3PlpSettings> getAtsc3PlpSettings(JNIEnv *env, const jobject &settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings");
     jobjectArray plpSettings =
             reinterpret_cast<jobjectArray>(
@@ -2549,13 +2591,12 @@
     int len = env->GetArrayLength(plpSettings);
 
     jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpSettings");
-    hidl_vec<FrontendAtsc3PlpSettings> plps = hidl_vec<FrontendAtsc3PlpSettings>(len);
+    vector<FrontendAtsc3PlpSettings> plps = vector<FrontendAtsc3PlpSettings>(len);
     // parse PLP settings
     for (int i = 0; i < len; i++) {
         jobject plp = env->GetObjectArrayElement(plpSettings, i);
-        uint8_t plpId =
-                static_cast<uint8_t>(
-                        env->GetIntField(plp, env->GetFieldID(plpClazz, "mPlpId", "I")));
+        int8_t plpId = static_cast<int8_t>(
+                env->GetIntField(plp, env->GetFieldID(plpClazz, "mPlpId", "I")));
         FrontendAtsc3Modulation modulation =
                 static_cast<FrontendAtsc3Modulation>(
                         env->GetIntField(plp, env->GetFieldID(plpClazz, "mModulation", "I")));
@@ -2583,9 +2624,10 @@
 
 static FrontendSettings getAtsc3FrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings");
-
     FrontendAtsc3Bandwidth bandwidth =
             static_cast<FrontendAtsc3Bandwidth>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I")));
@@ -2593,35 +2635,42 @@
             static_cast<FrontendAtsc3DemodOutputFormat>(
                     env->GetIntField(
                             settings, env->GetFieldID(clazz, "mDemodOutputFormat", "I")));
-    hidl_vec<FrontendAtsc3PlpSettings> plps = getAtsc3PlpSettings(env, settings);
-    FrontendAtsc3Settings frontendAtsc3Settings {
+    vector<FrontendAtsc3PlpSettings> plps = getAtsc3PlpSettings(env, settings);
+    FrontendAtsc3Settings frontendAtsc3Settings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .bandwidth = bandwidth,
             .demodOutputFormat = demod,
             .plpSettings = plps,
+            .inversion = inversion,
     };
-    frontendSettings.atsc3(frontendAtsc3Settings);
+    frontendSettings.set<FrontendSettings::Tag::atsc3>(frontendAtsc3Settings);
     return frontendSettings;
 }
 
 static FrontendSettings getAtscFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendSettings");
     FrontendAtscModulation modulation =
             static_cast<FrontendAtscModulation>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
-    FrontendAtscSettings frontendAtscSettings {
+    FrontendAtscSettings frontendAtscSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
+            .inversion = inversion,
     };
-    frontendSettings.atsc(frontendAtscSettings);
+    frontendSettings.set<FrontendSettings::Tag::atsc>(frontendAtscSettings);
     return frontendSettings;
 }
 
 static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings");
     FrontendDvbcModulation modulation =
             static_cast<FrontendDvbcModulation>(
@@ -2629,49 +2678,36 @@
     FrontendInnerFec innerFec =
             static_cast<FrontendInnerFec>(
                     env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J")));
-    uint32_t symbolRate =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
+    int32_t symbolRate = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
     FrontendDvbcOuterFec outerFec =
             static_cast<FrontendDvbcOuterFec>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I")));
     FrontendDvbcAnnex annex =
             static_cast<FrontendDvbcAnnex>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I")));
-    FrontendDvbcSpectralInversion spectralInversion =
-            static_cast<FrontendDvbcSpectralInversion>(
-                    env->GetIntField(
-                            settings, env->GetFieldID(clazz, "mSpectralInversion", "I")));
-    FrontendDvbcSettings frontendDvbcSettings {
+    FrontendSpectralInversion spectralInversion = static_cast<FrontendSpectralInversion>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mSpectralInversion", "I")));
+    FrontendCableTimeInterleaveMode interleaveMode = static_cast<FrontendCableTimeInterleaveMode>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mInterleaveMode", "I")));
+    FrontendDvbcBandwidth bandwidth = static_cast<FrontendDvbcBandwidth>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I")));
+    FrontendDvbcSettings frontendDvbcSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
             .fec = innerFec,
             .symbolRate = symbolRate,
             .outerFec = outerFec,
             .annex = annex,
-            .spectralInversion = spectralInversion,
+            .inversion = spectralInversion,
+            .interleaveMode = interleaveMode,
+            .bandwidth = bandwidth,
     };
-    frontendSettings.dvbc(frontendDvbcSettings);
+    frontendSettings.set<FrontendSettings::Tag::dvbc>(frontendDvbcSettings);
     return frontendSettings;
 }
 
-static void getDvbcFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
-        FrontendSettingsExt1_1& settingsExt1_1) {
-    jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings");
-    FrontendCableTimeInterleaveMode interleaveMode =
-            static_cast<FrontendCableTimeInterleaveMode>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mInterleaveMode", "I")));
-    FrontendDvbcBandwidth bandwidth =
-            static_cast<FrontendDvbcBandwidth>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I")));
-
-    FrontendDvbcSettingsExt1_1 dvbcExt1_1 {
-        .interleaveMode = interleaveMode,
-        .bandwidth = bandwidth,
-    };
-    settingsExt1_1.settingExt.dvbc(dvbcExt1_1);
-}
-
 static FrontendDvbsCodeRate getDvbsCodeRate(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
     jobject jcodeRate =
@@ -2694,11 +2730,8 @@
             static_cast<bool>(
                     env->GetBooleanField(
                             jcodeRate, env->GetFieldID(codeRateClazz, "mIsShortFrames", "Z")));
-    uint32_t bitsPer1000Symbol =
-            static_cast<uint32_t>(
-                    env->GetIntField(
-                            jcodeRate, env->GetFieldID(
-                                    codeRateClazz, "mBitsPer1000Symbol", "I")));
+    int32_t bitsPer1000Symbol = static_cast<int32_t>(
+            env->GetIntField(jcodeRate, env->GetFieldID(codeRateClazz, "mBitsPer1000Symbol", "I")));
     FrontendDvbsCodeRate coderate {
             .fec = innerFec,
             .isLinear = isLinear,
@@ -2710,33 +2743,37 @@
 
 static FrontendSettings getDvbsFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
-
     FrontendDvbsModulation modulation =
             static_cast<FrontendDvbsModulation>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
-    uint32_t symbolRate =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
+    int32_t symbolRate = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
     FrontendDvbsRolloff rolloff =
             static_cast<FrontendDvbsRolloff>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I")));
     FrontendDvbsPilot pilot =
             static_cast<FrontendDvbsPilot>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mPilot", "I")));
-    uint32_t inputStreamId =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mInputStreamId", "I")));
+    int32_t inputStreamId = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mInputStreamId", "I")));
     FrontendDvbsStandard standard =
             static_cast<FrontendDvbsStandard>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mStandard", "I")));
     FrontendDvbsVcmMode vcmMode =
             static_cast<FrontendDvbsVcmMode>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mVcmMode", "I")));
+    FrontendDvbsScanType scanType = static_cast<FrontendDvbsScanType>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
+    bool isDiseqcRxMessage = static_cast<bool>(
+            env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z")));
 
-    FrontendDvbsSettings frontendDvbsSettings {
+    FrontendDvbsSettings frontendDvbsSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
             .symbolRate = symbolRate,
             .rolloff = rolloff,
@@ -2744,37 +2781,26 @@
             .inputStreamId = inputStreamId,
             .standard = standard,
             .vcmMode = vcmMode,
+            .scanType = scanType,
+            .isDiseqcRxMessage = isDiseqcRxMessage,
+            .inversion = inversion,
     };
 
     jobject jcodeRate = env->GetObjectField(settings, env->GetFieldID(clazz, "mCodeRate",
             "Landroid/media/tv/tuner/frontend/DvbsCodeRate;"));
-    if (jcodeRate != NULL) {
+    if (jcodeRate != nullptr) {
         frontendDvbsSettings.coderate = getDvbsCodeRate(env, settings);
     }
 
-    frontendSettings.dvbs(frontendDvbsSettings);
+    frontendSettings.set<FrontendSettings::Tag::dvbs>(frontendDvbsSettings);
     return frontendSettings;
 }
 
-static void getDvbsFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
-        FrontendSettingsExt1_1& settingsExt1_1) {
-    jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
-    FrontendDvbsScanType scanType =
-            static_cast<FrontendDvbsScanType>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
-    bool isDiseqcRxMessage = static_cast<bool>(env->GetBooleanField(
-            settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z")));
-
-    FrontendDvbsSettingsExt1_1 dvbsExt1_1 {
-        .scanType = scanType,
-        .isDiseqcRxMessage = isDiseqcRxMessage,
-    };
-    settingsExt1_1.settingExt.dvbs(dvbsExt1_1);
-}
-
 static FrontendSettings getDvbtFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings");
     FrontendDvbtTransmissionMode transmissionMode =
             static_cast<FrontendDvbtTransmissionMode>(
@@ -2811,15 +2837,14 @@
     FrontendDvbtPlpMode plpMode =
             static_cast<FrontendDvbtPlpMode>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mPlpMode", "I")));
-    uint8_t plpId =
-            static_cast<uint8_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mPlpId", "I")));
-    uint8_t plpGroupId =
-            static_cast<uint8_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mPlpGroupId", "I")));
+    int8_t plpId =
+            static_cast<int8_t>(env->GetIntField(settings, env->GetFieldID(clazz, "mPlpId", "I")));
+    int8_t plpGroupId = static_cast<int8_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mPlpGroupId", "I")));
 
-    FrontendDvbtSettings frontendDvbtSettings {
+    FrontendDvbtSettings frontendDvbtSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .transmissionMode = transmissionMode,
             .bandwidth = bandwidth,
             .constellation = constellation,
@@ -2833,33 +2858,16 @@
             .plpMode = plpMode,
             .plpId = plpId,
             .plpGroupId = plpGroupId,
+            .inversion = inversion,
     };
-    frontendSettings.dvbt(frontendDvbtSettings);
+    frontendSettings.set<FrontendSettings::Tag::dvbt>(frontendDvbtSettings);
     return frontendSettings;
 }
 
-static void getDvbtFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
-        FrontendSettingsExt1_1& settingsExt1_1) {
-    jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings");
-
-    FrontendDvbtSettingsExt1_1 dvbtExt1_1;
-    int transmissionMode =
-            env->GetIntField(settings, env->GetFieldID(clazz, "mTransmissionMode", "I"));
-    dvbtExt1_1.transmissionMode = static_cast<
-            ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode>(
-                    transmissionMode);
-
-    int constellation =
-            env->GetIntField(settings, env->GetFieldID(clazz, "mConstellation", "I"));
-    dvbtExt1_1.constellation = static_cast<
-            ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation>(constellation);
-
-    settingsExt1_1.settingExt.dvbt(dvbtExt1_1);
-}
-
 static FrontendSettings getIsdbsFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendSettings");
     uint16_t streamId =
             static_cast<uint16_t>(
@@ -2873,15 +2881,15 @@
     FrontendIsdbsCoderate coderate =
             static_cast<FrontendIsdbsCoderate>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I")));
-    uint32_t symbolRate =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
+    int32_t symbolRate = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
     FrontendIsdbsRolloff rolloff =
             static_cast<FrontendIsdbsRolloff>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I")));
 
-    FrontendIsdbsSettings frontendIsdbsSettings {
+    FrontendIsdbsSettings frontendIsdbsSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .streamId = streamId,
             .streamIdType = streamIdType,
             .modulation = modulation,
@@ -2889,13 +2897,14 @@
             .symbolRate = symbolRate,
             .rolloff = rolloff,
     };
-    frontendSettings.isdbs(frontendIsdbsSettings);
+    frontendSettings.set<FrontendSettings::Tag::isdbs>(frontendIsdbsSettings);
     return frontendSettings;
 }
 
 static FrontendSettings getIsdbs3FrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendSettings");
     uint16_t streamId =
             static_cast<uint16_t>(
@@ -2909,15 +2918,15 @@
     FrontendIsdbs3Coderate coderate =
             static_cast<FrontendIsdbs3Coderate>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I")));
-    uint32_t symbolRate =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
+    int32_t symbolRate = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I")));
     FrontendIsdbs3Rolloff rolloff =
             static_cast<FrontendIsdbs3Rolloff>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I")));
 
-    FrontendIsdbs3Settings frontendIsdbs3Settings {
+    FrontendIsdbs3Settings frontendIsdbs3Settings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .streamId = streamId,
             .streamIdType = streamIdType,
             .modulation = modulation,
@@ -2925,13 +2934,15 @@
             .symbolRate = symbolRate,
             .rolloff = rolloff,
     };
-    frontendSettings.isdbs3(frontendIsdbs3Settings);
+    frontendSettings.set<FrontendSettings::Tag::isdbs3>(frontendIsdbs3Settings);
     return frontendSettings;
 }
 
 static FrontendSettings getIsdbtFrontendSettings(JNIEnv *env, const jobject& settings) {
     FrontendSettings frontendSettings;
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendSettings");
     FrontendIsdbtModulation modulation =
             static_cast<FrontendIsdbtModulation>(
@@ -2948,26 +2959,29 @@
     FrontendIsdbtGuardInterval guardInterval =
             static_cast<FrontendIsdbtGuardInterval>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I")));
-    uint32_t serviceAreaId =
-            static_cast<uint32_t>(
-                    env->GetIntField(settings, env->GetFieldID(clazz, "mServiceAreaId", "I")));
+    int32_t serviceAreaId = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mServiceAreaId", "I")));
 
-    FrontendIsdbtSettings frontendIsdbtSettings {
+    FrontendIsdbtSettings frontendIsdbtSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
             .bandwidth = bandwidth,
             .mode = mode,
             .coderate = coderate,
             .guardInterval = guardInterval,
             .serviceAreaId = serviceAreaId,
+            .inversion = inversion,
     };
-    frontendSettings.isdbt(frontendIsdbtSettings);
+    frontendSettings.set<FrontendSettings::Tag::isdbt>(frontendIsdbtSettings);
     return frontendSettings;
 }
 
-static void getDtmbFrontendSettings(JNIEnv *env, const jobject& settings,
-        FrontendSettingsExt1_1& settingsExt1_1) {
-    uint32_t freq = getFrontendSettingsFreq(env, settings);
+static FrontendSettings getDtmbFrontendSettings(JNIEnv *env, const jobject &settings) {
+    FrontendSettings frontendSettings;
+    int32_t freq = getFrontendSettingsFreq(env, settings);
+    int32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DtmbFrontendSettings");
     FrontendDtmbModulation modulation =
             static_cast<FrontendDtmbModulation>(
@@ -2988,25 +3002,23 @@
             static_cast<FrontendDtmbTimeInterleaveMode>(
                     env->GetIntField(settings, env->GetFieldID(clazz, "mTimeInterleaveMode", "I")));
 
-    FrontendDtmbSettings frontendDtmbSettings {
+    FrontendDtmbSettings frontendDtmbSettings{
             .frequency = freq,
+            .endFrequency = endFreq,
             .modulation = modulation,
             .bandwidth = bandwidth,
             .transmissionMode = transmissionMode,
             .codeRate = codeRate,
             .guardInterval = guardInterval,
             .interleaveMode = interleaveMode,
+            .inversion = inversion,
     };
-    settingsExt1_1.settingExt.dtmb(frontendDtmbSettings);
+    frontendSettings.set<FrontendSettings::Tag::dtmb>(frontendDtmbSettings);
+    return frontendSettings;
 }
 
 static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
-    ALOGD("getFrontendSettings %d", type);
-
-    if (type == static_cast<int>(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
-        return FrontendSettings();
-    }
-
+    ALOGV("getFrontendSettings %d", type);
     FrontendType feType = static_cast<FrontendType>(type);
     switch(feType) {
         case FrontendType::ANALOG:
@@ -3027,6 +3039,8 @@
             return getIsdbs3FrontendSettings(env, settings);
         case FrontendType::ISDBT:
             return getIsdbtFrontendSettings(env, settings);
+        case FrontendType::DTMB:
+            return getDtmbFrontendSettings(env, settings);
         default:
             // should never happen because a type is associated with a subclass of
             // FrontendSettings and not set by users
@@ -3036,64 +3050,6 @@
     }
 }
 
-static FrontendSettingsExt1_1 getFrontendSettingsExt1_1(
-        JNIEnv *env, int type, jobject settings, int tunerVersion) {
-    ALOGD("getFrontendSettingsExt1_1 %d", type);
-
-    FrontendSettingsExt1_1 settingsExt1_1 {
-        .endFrequency = static_cast<uint32_t>(Constant::INVALID_FRONTEND_SETTING_FREQUENCY),
-        .inversion = FrontendSpectralInversion::UNDEFINED,
-    };
-    settingsExt1_1.settingExt.noinit();
-
-    if (tunerVersion < TUNER_VERSION_1_1) {
-        return settingsExt1_1;
-    }
-
-    if (type == static_cast<int>(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) {
-        getDtmbFrontendSettings(env, settings, settingsExt1_1);
-    } else {
-        FrontendType feType = static_cast<FrontendType>(type);
-        switch(feType) {
-            case FrontendType::DVBS:
-                getDvbsFrontendSettingsExt1_1(env, settings, settingsExt1_1);
-                break;
-            case FrontendType::DVBT:
-                getDvbtFrontendSettingsExt1_1(env, settings, settingsExt1_1);
-                break;
-            case FrontendType::ANALOG:
-                getAnalogFrontendSettingsExt1_1(env, settings, settingsExt1_1);
-                break;
-            case FrontendType::ATSC3:
-                break;
-            case FrontendType::ATSC:
-                break;
-            case FrontendType::DVBC:
-                getDvbcFrontendSettingsExt1_1(env, settings, settingsExt1_1);
-                break;
-            case FrontendType::ISDBS:
-                break;
-            case FrontendType::ISDBS3:
-                break;
-            case FrontendType::ISDBT:
-                break;
-            default:
-                // should never happen because a type is associated with a subclass of
-                // FrontendSettings and not set by users
-                jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
-                    "Unsupported frontend type %d", type);
-                return FrontendSettingsExt1_1();
-        }
-    }
-
-    uint32_t endFreq = getFrontendSettingsEndFreq(env, settings);
-    FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
-    settingsExt1_1.endFrequency = endFreq;
-    settingsExt1_1.inversion = inversion;
-
-    return settingsExt1_1;
-}
-
 static sp<FilterClient> getFilterClient(JNIEnv *env, jobject filter) {
     return (FilterClient *)env->GetLongField(filter, gFields.filterContext);
 }
@@ -3105,18 +3061,14 @@
 static DvrSettings getDvrSettings(JNIEnv *env, jobject settings, bool isRecorder) {
     DvrSettings dvrSettings;
     jclass clazz = env->FindClass("android/media/tv/tuner/dvr/DvrSettings");
-    uint32_t statusMask =
-            static_cast<uint32_t>(env->GetIntField(
-                    settings, env->GetFieldID(clazz, "mStatusMask", "I")));
-    uint32_t lowThreshold =
-            static_cast<uint32_t>(env->GetLongField(
-                    settings, env->GetFieldID(clazz, "mLowThreshold", "J")));
-    uint32_t highThreshold =
-            static_cast<uint32_t>(env->GetLongField(
-                    settings, env->GetFieldID(clazz, "mHighThreshold", "J")));
-    uint8_t packetSize =
-            static_cast<uint8_t>(env->GetLongField(
-                    settings, env->GetFieldID(clazz, "mPacketSize", "J")));
+    int32_t statusMask = static_cast<int32_t>(
+            env->GetIntField(settings, env->GetFieldID(clazz, "mStatusMask", "I")));
+    int32_t lowThreshold = static_cast<int32_t>(
+            env->GetLongField(settings, env->GetFieldID(clazz, "mLowThreshold", "J")));
+    int32_t highThreshold = static_cast<int32_t>(
+            env->GetLongField(settings, env->GetFieldID(clazz, "mHighThreshold", "J")));
+    int8_t packetSize = static_cast<int8_t>(
+            env->GetLongField(settings, env->GetFieldID(clazz, "mPacketSize", "J")));
     DataFormat dataFormat =
             static_cast<DataFormat>(env->GetIntField(
                     settings, env->GetFieldID(clazz, "mDataFormat", "I")));
@@ -3128,7 +3080,7 @@
                 .dataFormat = dataFormat,
                 .packetSize = packetSize,
         };
-        dvrSettings.record(recordSettings);
+        dvrSettings.set<DvrSettings::Tag::record>(recordSettings);
     } else {
         PlaybackSettings PlaybackSettings {
                 .statusMask = statusMask,
@@ -3137,7 +3089,7 @@
                 .dataFormat = dataFormat,
                 .packetSize = packetSize,
         };
-        dvrSettings.playback(PlaybackSettings);
+        dvrSettings.set<DvrSettings::Tag::playback>(PlaybackSettings);
     }
     return dvrSettings;
 }
@@ -3152,10 +3104,10 @@
 
 static void android_media_tv_Tuner_native_init(JNIEnv *env) {
     jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
-    CHECK(clazz != NULL);
+    CHECK(clazz != nullptr);
 
     gFields.tunerContext = env->GetFieldID(clazz, "mNativeContext", "J");
-    CHECK(gFields.tunerContext != NULL);
+    CHECK(gFields.tunerContext != nullptr);
 
     gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
 
@@ -3229,12 +3181,16 @@
     return tuner->openFrontendByHandle(handle);
 }
 
+static int android_media_tv_Tuner_share_frontend(
+        JNIEnv *env, jobject thiz, jint id) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->shareFrontend(id);
+}
+
 static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
     sp<JTuner> tuner = getTuner(env, thiz);
     FrontendSettings setting = getFrontendSettings(env, type, settings);
-    FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(
-            env, type, settings, tuner->getTunerVersion());
-    return tuner->tune(setting, settingExt);
+    return tuner->tune(setting);
 }
 
 static int android_media_tv_Tuner_stop_tune(JNIEnv *env, jobject thiz) {
@@ -3246,9 +3202,7 @@
         JNIEnv *env, jobject thiz, jint settingsType, jobject settings, jint scanType) {
     sp<JTuner> tuner = getTuner(env, thiz);
     FrontendSettings setting = getFrontendSettings(env, settingsType, settings);
-    FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(
-            env, settingsType, settings, tuner->getTunerVersion());
-    return tuner->scan(setting, static_cast<FrontendScanType>(scanType), settingExt);
+    return tuner->scan(setting, static_cast<FrontendScanType>(scanType));
 }
 
 static int android_media_tv_Tuner_stop_scan(JNIEnv *env, jobject thiz) {
@@ -3259,7 +3213,7 @@
 static int android_media_tv_Tuner_set_lnb(JNIEnv *env, jobject thiz, jobject lnb) {
     sp<JTuner> tuner = getTuner(env, thiz);
     sp<LnbClient> lnbClient = getLnbClient(env, lnb);
-    if (lnbClient == NULL) {
+    if (lnbClient == nullptr) {
         ALOGE("lnb is not initialized");
         return (int)Result::INVALID_STATE;
     }
@@ -3280,9 +3234,9 @@
 static jobject android_media_tv_Tuner_get_av_sync_hw_id(
         JNIEnv *env, jobject thiz, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to get sync ID. Filter client not found");
-        return NULL;
+        return nullptr;
     }
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->getAvSyncHwId(filterClient);
@@ -3337,22 +3291,30 @@
         .mainType = mainType,
     };
 
-    switch(mainType) {
+    switch (mainType) {
         case DemuxFilterMainType::TS:
-            filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+            filterType.subType.set<DemuxFilterSubType::Tag::tsFilterType>(
+                    static_cast<DemuxTsFilterType>(subType));
             break;
         case DemuxFilterMainType::MMTP:
-            filterType.subType.mmtpFilterType(static_cast<DemuxMmtpFilterType>(subType));
+            filterType.subType.set<DemuxFilterSubType::Tag::mmtpFilterType>(
+                    static_cast<DemuxMmtpFilterType>(subType));
             break;
         case DemuxFilterMainType::IP:
-            filterType.subType.ipFilterType(static_cast<DemuxIpFilterType>(subType));
+            filterType.subType.set<DemuxFilterSubType::Tag::ipFilterType>(
+                    static_cast<DemuxIpFilterType>(subType));
             break;
         case DemuxFilterMainType::TLV:
-            filterType.subType.tlvFilterType(static_cast<DemuxTlvFilterType>(subType));
+            filterType.subType.set<DemuxFilterSubType::Tag::tlvFilterType>(
+                    static_cast<DemuxTlvFilterType>(subType));
             break;
         case DemuxFilterMainType::ALP:
-            filterType.subType.alpFilterType(static_cast<DemuxAlpFilterType>(subType));
+            filterType.subType.set<DemuxFilterSubType::Tag::alpFilterType>(
+                    static_cast<DemuxAlpFilterType>(subType));
             break;
+        default:
+            ALOGD("Demux Filter Main Type is undefined.");
+            return nullptr;
     }
 
     return tuner->openFilter(filterType, bufferSize);
@@ -3392,16 +3354,16 @@
     return filterSectionBits;
 }
 
-static DemuxFilterSectionSettings::Condition::TableInfo getFilterTableInfo(
-        JNIEnv *env, const jobject& settings) {
+static DemuxFilterSectionSettingsConditionTableInfo getFilterTableInfo(JNIEnv *env,
+                                                                       const jobject &settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo");
     uint16_t tableId = static_cast<uint16_t>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mTableId", "I")));
     uint16_t version = static_cast<uint16_t>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mVersion", "I")));
-    DemuxFilterSectionSettings::Condition::TableInfo tableInfo {
-        .tableId = tableId,
-        .version = version,
+    DemuxFilterSectionSettingsConditionTableInfo tableInfo{
+            .tableId = tableId,
+            .version = version,
     };
     return tableInfo;
 }
@@ -3423,11 +3385,13 @@
     if (env->IsInstanceOf(
             settings,
             env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithSectionBits"))) {
-        filterSectionSettings.condition.sectionBits(getFilterSectionBits(env, settings));
+        filterSectionSettings.condition.set<DemuxFilterSectionSettingsCondition::Tag::sectionBits>(
+                getFilterSectionBits(env, settings));
     } else if (env->IsInstanceOf(
             settings,
             env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo"))) {
-        filterSectionSettings.condition.tableInfo(getFilterTableInfo(env, settings));
+        filterSectionSettings.condition.set<DemuxFilterSectionSettingsCondition::Tag::tableInfo>(
+                getFilterTableInfo(env, settings));
     }
     return filterSectionSettings;
 }
@@ -3455,13 +3419,13 @@
     AudioStreamType audioStreamType = static_cast<AudioStreamType>(
             env->GetIntField(settingsObj, env->GetFieldID(clazz, "mAudioStreamType", "I")));
     if (audioStreamType != AudioStreamType::UNDEFINED) {
-        type.audio(audioStreamType);
+        type.set<AvStreamType::Tag::audio>(audioStreamType);
         return true;
     }
     VideoStreamType videoStreamType = static_cast<VideoStreamType>(
             env->GetIntField(settingsObj, env->GetFieldID(clazz, "mVideoStreamType", "I")));
     if (videoStreamType != VideoStreamType::UNDEFINED) {
-        type.video(videoStreamType);
+        type.set<AvStreamType::Tag::video>(videoStreamType);
         return true;
     }
     return false;
@@ -3482,7 +3446,7 @@
 
 static DemuxFilterRecordSettings getFilterRecordSettings(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/RecordSettings");
-    hidl_bitfield<DemuxTsIndex> tsIndexMask = static_cast<hidl_bitfield<DemuxTsIndex>>(
+    int32_t tsIndexMask = static_cast<int32_t>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mTsIndexMask", "I")));
     DemuxRecordScIndexType scIndexType = static_cast<DemuxRecordScIndexType>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexType", "I")));
@@ -3493,17 +3457,16 @@
         .scIndexType = scIndexType,
     };
     if (scIndexType == DemuxRecordScIndexType::SC) {
-        filterRecordSettings.scIndexMask.sc(static_cast<hidl_bitfield<DemuxScIndex>>(scIndexMask));
+        filterRecordSettings.scIndexMask.set<DemuxFilterScIndexMask::Tag::scIndex>(scIndexMask);
     } else if (scIndexType == DemuxRecordScIndexType::SC_HEVC) {
-        filterRecordSettings.scIndexMask.scHevc(
-                static_cast<hidl_bitfield<DemuxScHevcIndex>>(scIndexMask));
+        filterRecordSettings.scIndexMask.set<DemuxFilterScIndexMask::Tag::scHevc>(scIndexMask);
     }
     return filterRecordSettings;
 }
 
 static DemuxFilterDownloadSettings getFilterDownloadSettings(JNIEnv *env, const jobject& settings) {
     jclass clazz = env->FindClass("android/media/tv/tuner/filter/DownloadSettings");
-    uint32_t downloadId = static_cast<uint32_t>(
+    int32_t downloadId = static_cast<int32_t>(
             env->GetIntField(settings, env->GetFieldID(clazz, "mDownloadId", "I")));
 
     DemuxFilterDownloadSettings filterDownloadSettings {
@@ -3532,23 +3495,23 @@
     }
 
     if (srcSize == IP_V4_LENGTH) {
-        uint8_t srcAddr[IP_V4_LENGTH];
-        uint8_t dstAddr[IP_V4_LENGTH];
-        env->GetByteArrayRegion(
-                jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte*>(srcAddr));
-        env->GetByteArrayRegion(
-                jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte*>(dstAddr));
-        res.srcIpAddress.v4(srcAddr);
-        res.dstIpAddress.v4(dstAddr);
+        vector<uint8_t> srcAddr;
+        vector<uint8_t> dstAddr;
+        srcAddr.resize(IP_V4_LENGTH);
+        dstAddr.resize(IP_V4_LENGTH);
+        env->GetByteArrayRegion(jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte *>(&srcAddr[0]));
+        env->GetByteArrayRegion(jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte *>(&dstAddr[0]));
+        res.srcIpAddress.set<DemuxIpAddressIpAddress::Tag::v4>(srcAddr);
+        res.dstIpAddress.set<DemuxIpAddressIpAddress::Tag::v4>(dstAddr);
     } else if (srcSize == IP_V6_LENGTH) {
-        uint8_t srcAddr[IP_V6_LENGTH];
-        uint8_t dstAddr[IP_V6_LENGTH];
-        env->GetByteArrayRegion(
-                jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte*>(srcAddr));
-        env->GetByteArrayRegion(
-                jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte*>(dstAddr));
-        res.srcIpAddress.v6(srcAddr);
-        res.dstIpAddress.v6(dstAddr);
+        vector<uint8_t> srcAddr;
+        vector<uint8_t> dstAddr;
+        srcAddr.resize(IP_V6_LENGTH);
+        dstAddr.resize(IP_V6_LENGTH);
+        env->GetByteArrayRegion(jsrcIpAddress, 0, srcSize, reinterpret_cast<jbyte *>(&srcAddr[0]));
+        env->GetByteArrayRegion(jdstIpAddress, 0, dstSize, reinterpret_cast<jbyte *>(&dstAddr[0]));
+        res.srcIpAddress.set<DemuxIpAddressIpAddress::Tag::v6>(srcAddr);
+        res.dstIpAddress.set<DemuxIpAddressIpAddress::Tag::v6>(dstAddr);
     } else {
         // should never happen. Validated on Java size.
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
@@ -3556,10 +3519,10 @@
         return res;
     }
 
-    uint16_t srcPort = static_cast<uint16_t>(
-            env->GetIntField(config, env->GetFieldID(clazz, "mSrcPort", "I")));
-    uint16_t dstPort = static_cast<uint16_t>(
-            env->GetIntField(config, env->GetFieldID(clazz, "mDstPort", "I")));
+    int16_t srcPort =
+            static_cast<int16_t>(env->GetIntField(config, env->GetFieldID(clazz, "mSrcPort", "I")));
+    int16_t dstPort =
+            static_cast<int16_t>(env->GetIntField(config, env->GetFieldID(clazz, "mDstPort", "I")));
 
     res.srcPort = srcPort;
     res.dstPort = dstPort;
@@ -3587,30 +3550,35 @@
                 .tpid = tpid,
             };
 
-            if (settingsObj != NULL) {
+            if (settingsObj != nullptr) {
                 DemuxTsFilterType tsType = static_cast<DemuxTsFilterType>(subtype);
                 switch (tsType) {
                     case DemuxTsFilterType::SECTION:
-                        tsFilterSettings.filterSettings.section(
-                                getFilterSectionSettings(env, settingsObj));
+                        tsFilterSettings.filterSettings
+                                .set<DemuxTsFilterSettingsFilterSettings::Tag::section>(
+                                        getFilterSectionSettings(env, settingsObj));
                         break;
                     case DemuxTsFilterType::AUDIO:
                     case DemuxTsFilterType::VIDEO:
-                        tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+                        tsFilterSettings.filterSettings
+                                .set<DemuxTsFilterSettingsFilterSettings::Tag::av>(
+                                        getFilterAvSettings(env, settingsObj));
                         break;
                     case DemuxTsFilterType::PES:
-                        tsFilterSettings.filterSettings.pesData(
-                                getFilterPesDataSettings(env, settingsObj));
+                        tsFilterSettings.filterSettings
+                                .set<DemuxTsFilterSettingsFilterSettings::Tag::pesData>(
+                                        getFilterPesDataSettings(env, settingsObj));
                         break;
                     case DemuxTsFilterType::RECORD:
-                        tsFilterSettings.filterSettings.record(
-                                getFilterRecordSettings(env, settingsObj));
+                        tsFilterSettings.filterSettings
+                                .set<DemuxTsFilterSettingsFilterSettings::Tag::record>(
+                                        getFilterRecordSettings(env, settingsObj));
                         break;
                     default:
                         break;
                 }
             }
-            filterSettings.ts(tsFilterSettings);
+            filterSettings.set<DemuxFilterSettings::Tag::ts>(tsFilterSettings);
             break;
         }
         case DemuxFilterMainType::MMTP: {
@@ -3621,34 +3589,40 @@
                 .mmtpPid = mmtpPid,
             };
 
-            if (settingsObj != NULL) {
+            if (settingsObj != nullptr) {
                 DemuxMmtpFilterType mmtpType = static_cast<DemuxMmtpFilterType>(subtype);
                 switch (mmtpType) {
                     case DemuxMmtpFilterType::SECTION:
-                        mmtpFilterSettings.filterSettings.section(
-                                getFilterSectionSettings(env, settingsObj));
+                        mmtpFilterSettings.filterSettings
+                                .set<DemuxMmtpFilterSettingsFilterSettings::Tag::section>(
+                                        getFilterSectionSettings(env, settingsObj));
                         break;
                     case DemuxMmtpFilterType::AUDIO:
                     case DemuxMmtpFilterType::VIDEO:
-                        mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj));
+                        mmtpFilterSettings.filterSettings
+                                .set<DemuxMmtpFilterSettingsFilterSettings::Tag::av>(
+                                        getFilterAvSettings(env, settingsObj));
                         break;
                     case DemuxMmtpFilterType::PES:
-                        mmtpFilterSettings.filterSettings.pesData(
-                                getFilterPesDataSettings(env, settingsObj));
+                        mmtpFilterSettings.filterSettings
+                                .set<DemuxMmtpFilterSettingsFilterSettings::Tag::pesData>(
+                                        getFilterPesDataSettings(env, settingsObj));
                         break;
                     case DemuxMmtpFilterType::RECORD:
-                        mmtpFilterSettings.filterSettings.record(
-                                getFilterRecordSettings(env, settingsObj));
+                        mmtpFilterSettings.filterSettings
+                                .set<DemuxMmtpFilterSettingsFilterSettings::Tag::record>(
+                                        getFilterRecordSettings(env, settingsObj));
                         break;
                     case DemuxMmtpFilterType::DOWNLOAD:
-                        mmtpFilterSettings.filterSettings.download(
-                                getFilterDownloadSettings(env, settingsObj));
+                        mmtpFilterSettings.filterSettings
+                                .set<DemuxMmtpFilterSettingsFilterSettings::Tag::download>(
+                                        getFilterDownloadSettings(env, settingsObj));
                         break;
                     default:
                         break;
                 }
             }
-            filterSettings.mmtp(mmtpFilterSettings);
+            filterSettings.set<DemuxFilterSettings::Tag::mmtp>(mmtpFilterSettings);
             break;
         }
         case DemuxFilterMainType::IP: {
@@ -3658,8 +3632,9 @@
             };
 
             DemuxIpFilterType ipType = static_cast<DemuxIpFilterType>(subtype);
-            if (ipType == DemuxIpFilterType::SECTION && settingsObj != NULL) {
-                ipFilterSettings.filterSettings.section(
+            if (ipType == DemuxIpFilterType::SECTION && settingsObj != nullptr) {
+                ipFilterSettings.filterSettings
+                        .set<DemuxIpFilterSettingsFilterSettings::Tag::section>(
                                 getFilterSectionSettings(env, settingsObj));
             } else if (ipType == DemuxIpFilterType::IP) {
                 jclass clazz = env->FindClass(
@@ -3668,14 +3643,15 @@
                         env->GetBooleanField(
                                 filterConfigObj, env->GetFieldID(
                                         clazz, "mPassthrough", "Z")));
-                ipFilterSettings.filterSettings.bPassthrough(bPassthrough);
+                ipFilterSettings.filterSettings
+                        .set<DemuxIpFilterSettingsFilterSettings::Tag::bPassthrough>(bPassthrough);
             }
-            filterSettings.ip(ipFilterSettings);
+            filterSettings.set<DemuxFilterSettings::Tag::ip>(ipFilterSettings);
             break;
         }
         case DemuxFilterMainType::TLV: {
             jclass clazz = env->FindClass("android/media/tv/tuner/filter/TlvFilterConfiguration");
-            uint8_t packetType = static_cast<uint8_t>(
+            int8_t packetType = static_cast<int8_t>(
                     env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
             bool isCompressedIpPacket = static_cast<bool>(
                     env->GetBooleanField(
@@ -3687,22 +3663,24 @@
             };
 
             DemuxTlvFilterType tlvType = static_cast<DemuxTlvFilterType>(subtype);
-            if (tlvType == DemuxTlvFilterType::SECTION && settingsObj != NULL) {
-                tlvFilterSettings.filterSettings.section(
-                        getFilterSectionSettings(env, settingsObj));
+            if (tlvType == DemuxTlvFilterType::SECTION && settingsObj != nullptr) {
+                tlvFilterSettings.filterSettings
+                        .set<DemuxTlvFilterSettingsFilterSettings::Tag::section>(
+                                getFilterSectionSettings(env, settingsObj));
             } else if (tlvType == DemuxTlvFilterType::TLV) {
                 bool bPassthrough = static_cast<bool>(
                 env->GetBooleanField(
                         filterConfigObj, env->GetFieldID(
                                 clazz, "mPassthrough", "Z")));
-                tlvFilterSettings.filterSettings.bPassthrough(bPassthrough);
+                tlvFilterSettings.filterSettings
+                        .set<DemuxTlvFilterSettingsFilterSettings::Tag::bPassthrough>(bPassthrough);
             }
-            filterSettings.tlv(tlvFilterSettings);
+            filterSettings.set<DemuxFilterSettings::Tag::tlv>(tlvFilterSettings);
             break;
         }
         case DemuxFilterMainType::ALP: {
             jclass clazz = env->FindClass("android/media/tv/tuner/filter/AlpFilterConfiguration");
-            uint8_t packetType = static_cast<uint8_t>(
+            int8_t packetType = static_cast<int8_t>(
                     env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I")));
             DemuxAlpLengthType lengthType = static_cast<DemuxAlpLengthType>(
                     env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mLengthType", "I")));
@@ -3711,18 +3689,19 @@
                 .lengthType = lengthType,
             };
 
-            if (settingsObj != NULL) {
+            if (settingsObj != nullptr) {
                 DemuxAlpFilterType alpType = static_cast<DemuxAlpFilterType>(subtype);
                 switch (alpType) {
                     case DemuxAlpFilterType::SECTION:
-                        alpFilterSettings.filterSettings.section(
-                                getFilterSectionSettings(env, settingsObj));
+                        alpFilterSettings.filterSettings
+                                .set<DemuxAlpFilterSettingsFilterSettings::Tag::section>(
+                                        getFilterSectionSettings(env, settingsObj));
                         break;
                     default:
                         break;
                 }
             }
-            filterSettings.alp(alpFilterSettings);
+            filterSettings.set<DemuxFilterSettings::Tag::alp>(alpFilterSettings);
             break;
         }
         default: {
@@ -3743,34 +3722,33 @@
 }
 
 static bool isAvFilterSettings(DemuxFilterSettings filterSettings) {
-    return (filterSettings.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::ts
-            && filterSettings.ts().filterSettings.getDiscriminator()
-                    == DemuxTsFilterSettings::FilterSettings::hidl_discriminator::av)
-            ||
-            (filterSettings.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::mmtp
-            && filterSettings.mmtp().filterSettings.getDiscriminator()
-                    == DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::av);
+    return (filterSettings.getTag() == DemuxFilterSettings::Tag::ts &&
+            filterSettings.get<DemuxFilterSettings::Tag::ts>().filterSettings.getTag() ==
+                    DemuxTsFilterSettingsFilterSettings::Tag::av) ||
+            (filterSettings.getTag() == DemuxFilterSettings::Tag::mmtp &&
+             filterSettings.get<DemuxFilterSettings::Tag::mmtp>().filterSettings.getTag() ==
+                     DemuxMmtpFilterSettingsFilterSettings::Tag::av);
 }
 
 static jint android_media_tv_Tuner_configure_filter(
         JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
-    ALOGD("configure filter type=%d, subtype=%d", type, subtype);
+    ALOGV("configure filter type=%d, subtype=%d", type, subtype);
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to configure filter: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+        return (jint)Result::NOT_INITIALIZED;
     }
     DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings);
     Result res = filterClient->configure(filterSettings);
 
     if (res != Result::SUCCESS) {
-        return (jint) res;
+        return (jint)res;
     }
 
     if (static_cast<DemuxFilterMainType>(type) == DemuxFilterMainType::IP) {
         res = configureIpFilterContextId(env, filterClient, settings);
         if (res != Result::SUCCESS) {
-            return (jint) res;
+            return (jint)res;
         }
     }
 
@@ -3778,99 +3756,98 @@
     if (isAvFilterSettings(filterSettings) && getAvStreamType(env, settings, streamType)) {
         res = filterClient->configureAvStreamType(streamType);
     }
-    return (jint) res;
+    return (jint)res;
 }
 
 static jint android_media_tv_Tuner_get_filter_id(JNIEnv* env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to get filter ID: filter client not found");
         return (int) Result::NOT_INITIALIZED;
     }
-    uint32_t id;
+    int32_t id;
     Result res = filterClient->getId(id);
     if (res != Result::SUCCESS) {
-        return (jint) Constant::INVALID_FILTER_ID;
+        return (jint)Constant::INVALID_FILTER_ID;
     }
-    return (jint) id;
+    return (jint)id;
 }
 
 static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to get filter ID 64 bit: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
-    uint64_t id;
+    int64_t id;
     Result res = filterClient->getId64Bit(id);
-    return (res == Result::SUCCESS) ?
-            static_cast<jlong>(id) : static_cast<jlong>(
-                    ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+    return (res == Result::SUCCESS) ? static_cast<jlong>(id)
+                                    : static_cast<jlong>(Constant64Bit::INVALID_FILTER_ID_64BIT);
 }
 
 static jint android_media_tv_Tuner_configure_monitor_event(
         JNIEnv* env, jobject filter, int monitorEventType) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to configure scrambling event: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
     Result res = filterClient->configureMonitorEvent(monitorEventType);
-    return (jint) res;
+    return (jint)res;
 }
 
 static jint android_media_tv_Tuner_set_filter_data_source(
         JNIEnv* env, jobject filter, jobject srcFilter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to set filter data source: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
     Result res;
-    if (srcFilter == NULL) {
-        res = filterClient->setDataSource(NULL);
+    if (srcFilter == nullptr) {
+        res = filterClient->setDataSource(nullptr);
     } else {
         sp<FilterClient> srcClient = getFilterClient(env, srcFilter);
-        if (srcClient == NULL) {
+        if (srcClient == nullptr) {
             ALOGD("Failed to set filter data source: src filter not found");
-            return (jint) Result::INVALID_ARGUMENT;
+            return (jint)Result::INVALID_ARGUMENT;
         }
         res = filterClient->setDataSource(srcClient);
     }
-    return (jint) res;
+    return (jint)res;
 }
 
 static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to start filter: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
-    return (jint) filterClient->start();
+    return (jint)filterClient->start();
 }
 
 static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to stop filter: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
-    return (jint) filterClient->stop();
+    return (jint)filterClient->stop();
 }
 
 static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         ALOGD("Failed to flush filter: filter client not found");
-        return (int) Result::NOT_INITIALIZED;
+        return (int)Result::NOT_INITIALIZED;
     }
-    return (jint) filterClient->flush();
+    return (jint)filterClient->flush();
 }
 
 static jint android_media_tv_Tuner_read_filter_fmq(
         JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Failed to read filter FMQ: filter client not found");
         return -1;
@@ -3878,25 +3855,25 @@
 
     jboolean isCopy;
     jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
-    ALOGD("copyData, isCopy=%d", isCopy);
+    ALOGV("copyData, isCopy=%d", isCopy);
     if (dst == nullptr) {
         jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
         return -1;
     }
     int realReadSize = filterClient->read(reinterpret_cast<int8_t*>(dst) + offset, size);
     env->ReleaseByteArrayElements(buffer, dst, 0);
-    return (jint) realReadSize;
+    return (jint)realReadSize;
 }
 
 static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
+    if (filterClient == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Failed to close filter: filter client not found");
         return 0;
     }
 
-    return (jint) filterClient->close();
+    return (jint)filterClient->close();
 }
 
 static sp<TimeFilterClient> getTimeFilterClient(JNIEnv *env, jobject filter) {
@@ -3906,33 +3883,31 @@
 static int android_media_tv_Tuner_time_filter_set_timestamp(
         JNIEnv *env, jobject filter, jlong timestamp) {
     sp<TimeFilterClient> timeFilterClient = getTimeFilterClient(env, filter);
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed set timestamp: time filter client not found");
         return (int) Result::INVALID_STATE;
     }
-    Result r = timeFilterClient->setTimeStamp(static_cast<uint64_t>(timestamp));
-    return (int) r;
+    return (int)timeFilterClient->setTimeStamp(static_cast<int64_t>(timestamp));
 }
 
 static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) {
     sp<TimeFilterClient> timeFilterClient = getTimeFilterClient(env, filter);
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed clear timestamp: time filter client not found");
         return (int) Result::INVALID_STATE;
     }
-    Result r = timeFilterClient->clearTimeStamp();
-    return (int) r;
+    return (int)timeFilterClient->clearTimeStamp();
 }
 
 static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) {
     sp<TimeFilterClient> timeFilterClient = getTimeFilterClient(env, filter);
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed get timestamp: time filter client not found");
-        return NULL;
+        return nullptr;
     }
-    uint64_t timestamp = timeFilterClient->getTimeStamp();
+    int64_t timestamp = timeFilterClient->getTimeStamp();
     if (timestamp == (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP) {
-        return NULL;
+        return nullptr;
     }
 
     jclass longClazz = env->FindClass("java/lang/Long");
@@ -3944,13 +3919,13 @@
 
 static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) {
     sp<TimeFilterClient> timeFilterClient = getTimeFilterClient(env, filter);
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed get source time: time filter client not found");
-        return NULL;
+        return nullptr;
     }
-    uint64_t timestamp = timeFilterClient->getSourceTime();
+    int64_t timestamp = timeFilterClient->getSourceTime();
     if (timestamp == (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP) {
-        return NULL;
+        return nullptr;
     }
 
     jclass longClazz = env->FindClass("java/lang/Long");
@@ -3962,7 +3937,7 @@
 
 static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) {
     sp<TimeFilterClient> timeFilterClient = getTimeFilterClient(env, filter);
-    if (timeFilterClient == NULL) {
+    if (timeFilterClient == nullptr) {
         ALOGD("Failed close time filter: time filter client not found");
         return (int) Result::INVALID_STATE;
     }
@@ -3972,7 +3947,7 @@
         timeFilterClient->decStrong(filter);
         env->SetLongField(filter, gFields.timeFilterContext, 0);
     }
-    return (int) r;
+    return (int)r;
 }
 
 static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jint) {
@@ -3983,48 +3958,48 @@
 static jint android_media_tv_Tuner_descrambler_add_pid(
         JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
     sp<DescramblerClient> descramblerClient = getDescramblerClient(env, descrambler);
-    if (descramblerClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (descramblerClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
-    sp<FilterClient> filterClient = (filter == NULL) ? NULL : getFilterClient(env, filter);
+    sp<FilterClient> filterClient = (filter == nullptr) ? nullptr : getFilterClient(env, filter);
     Result result = descramblerClient->addPid(getDemuxPid((int)pidType, (int)pid), filterClient);
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_descrambler_remove_pid(
         JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
     sp<DescramblerClient> descramblerClient = getDescramblerClient(env, descrambler);
-    if (descramblerClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (descramblerClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
-    sp<FilterClient> filterClient = (filter == NULL) ? NULL : getFilterClient(env, filter);
+    sp<FilterClient> filterClient = (filter == nullptr) ? nullptr : getFilterClient(env, filter);
     Result result = descramblerClient->removePid(getDemuxPid((int)pidType, (int)pid), filterClient);
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_descrambler_set_key_token(
         JNIEnv* env, jobject descrambler, jbyteArray keyToken) {
     sp<DescramblerClient> descramblerClient = getDescramblerClient(env, descrambler);
-    if (descramblerClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (descramblerClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
     int size = env->GetArrayLength(keyToken);
     std::vector<uint8_t> v(size);
     env->GetByteArrayRegion(keyToken, 0, size, reinterpret_cast<jbyte*>(&v[0]));
     Result result = descramblerClient->setKeyToken(v);
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_close_descrambler(JNIEnv* env, jobject descrambler) {
     sp<DescramblerClient> descramblerClient = getDescramblerClient(env, descrambler);
-    if (descramblerClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (descramblerClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result r = descramblerClient->close();
     if (r == Result::SUCCESS) {
         descramblerClient->decStrong(descrambler);
     }
-    return (jint) r;
+    return (jint)r;
 }
 
 static jobject android_media_tv_Tuner_open_dvr_recorder(
@@ -4046,13 +4021,13 @@
 
 static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
-    return (jint) tuner->openDemux(handle);
+    return (jint)tuner->openDemux(handle);
 }
 
 static jint android_media_tv_Tuner_close_tuner(JNIEnv* env, jobject thiz) {
     sp<JTuner> tuner = getTuner(env, thiz);
-    setTuner(env, thiz, NULL);
-    return (jint) tuner->close();
+    setTuner(env, thiz, nullptr);
+    return (jint)tuner->close();
 }
 
 static jint android_media_tv_Tuner_close_demux(JNIEnv* env, jobject thiz, jint /* handle */) {
@@ -4067,97 +4042,94 @@
 
 static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
-        return (jint) Result::INVALID_ARGUMENT;
+    if (filterClient == nullptr) {
+        return (jint)Result::INVALID_ARGUMENT;
     }
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (dvrClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result result = dvrClient->attachFilter(filterClient);
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
     sp<FilterClient> filterClient = getFilterClient(env, filter);
-    if (filterClient == NULL) {
-        return (jint) Result::INVALID_ARGUMENT;
+    if (filterClient == nullptr) {
+        return (jint)Result::INVALID_ARGUMENT;
     }
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
-        return (jint) Result::NOT_INITIALIZED;
+    if (dvrClient == nullptr) {
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result result = dvrClient->detachFilter(filterClient);
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to configure dvr: dvr client not found");
         return (int)Result::NOT_INITIALIZED;
     }
     bool isRecorder =
             env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
     Result result = dvrClient->configure(getDvrSettings(env, settings, isRecorder));
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to start dvr: dvr client not found");
-        return (jint) Result::NOT_INITIALIZED;
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result result = dvrClient->start();
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to stop dvr: dvr client not found");
-        return (jint) Result::NOT_INITIALIZED;
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result result = dvrClient->stop();
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to flush dvr: dvr client not found");
-        return (jint) Result::NOT_INITIALIZED;
+        return (jint)Result::NOT_INITIALIZED;
     }
     Result result = dvrClient->flush();
-    return (jint) result;
+    return (jint)result;
 }
 
 static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to close dvr: dvr client not found");
-        return (jint) Result::NOT_INITIALIZED;
+        return (jint)Result::NOT_INITIALIZED;
     }
-    return (jint) dvrClient->close();
+    return (jint)dvrClient->close();
 }
 
 static jint android_media_tv_Tuner_lnb_set_voltage(JNIEnv* env, jobject lnb, jint voltage) {
     sp<LnbClient> lnbClient = getLnbClient(env, lnb);
-    Result r = lnbClient->setVoltage(static_cast<LnbVoltage>(voltage));
-    return (jint) r;
+    return (jint)lnbClient->setVoltage(static_cast<LnbVoltage>(voltage));
 }
 
 static int android_media_tv_Tuner_lnb_set_tone(JNIEnv* env, jobject lnb, jint tone) {
     sp<LnbClient> lnbClient = getLnbClient(env, lnb);
-    Result r = lnbClient->setTone(static_cast<LnbTone>(tone));
-    return (jint) r;
+    return (jint)lnbClient->setTone(static_cast<LnbTone>(tone));
 }
 
 static int android_media_tv_Tuner_lnb_set_position(JNIEnv* env, jobject lnb, jint position) {
     sp<LnbClient> lnbClient = getLnbClient(env, lnb);
-    Result r = lnbClient->setSatellitePosition(static_cast<LnbPosition>(position));
-    return (jint) r;
+    return (jint)lnbClient->setSatellitePosition(static_cast<LnbPosition>(position));
 }
 
 static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv* env, jobject lnb, jbyteArray msg) {
@@ -4165,8 +4137,7 @@
     int size = env->GetArrayLength(msg);
     std::vector<uint8_t> v(size);
     env->GetByteArrayRegion(msg, 0, size, reinterpret_cast<jbyte*>(&v[0]));
-    Result r = lnbClient->sendDiseqcMessage(v);
-    return (jint) r;
+    return (jint)lnbClient->sendDiseqcMessage(v);
 }
 
 static int android_media_tv_Tuner_close_lnb(JNIEnv* env, jobject lnb) {
@@ -4176,34 +4147,34 @@
         lnbClient->decStrong(lnb);
         env->SetLongField(lnb, gFields.lnbContext, 0);
     }
-    return (jint) r;
+    return (jint)r;
 }
 
 static void android_media_tv_Tuner_dvr_set_fd(JNIEnv *env, jobject dvr, jint fd) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGD("Failed to set FD for dvr: dvr client not found");
         return;
     }
     dvrClient->setFd((int)fd);
-    ALOGD("set fd = %d", fd);
+    ALOGV("set fd = %d", fd);
 }
 
 static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong size) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Failed to read dvr: dvr client not found");
         return -1;
     }
 
-    return (jlong) dvrClient->readFromFile(size);
+    return (jlong)dvrClient->readFromFile(size);
 }
 
 static jlong android_media_tv_Tuner_read_dvr_from_array(
         JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGW("Failed to read dvr: dvr client not found");
         return -1;
     }
@@ -4216,32 +4187,31 @@
     }
     long realSize = dvrClient->readFromBuffer(reinterpret_cast<signed char*>(src) + offset, size);
     env->ReleaseByteArrayElements(buffer, src, 0);
-    return (jlong) realSize;
-
+    return (jlong)realSize;
 }
 
 static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Failed to write dvr: dvr client not found");
         return -1;
     }
 
-    return (jlong) dvrClient->writeToFile(size);
+    return (jlong)dvrClient->writeToFile(size);
 }
 
 static jlong android_media_tv_Tuner_write_dvr_to_array(
         JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
     sp<DvrClient> dvrClient = getDvrClient(env, dvr);
-    if (dvrClient == NULL) {
+    if (dvrClient == nullptr) {
         ALOGW("Failed to read dvr: dvr client not found");
         return -1;
     }
 
     jboolean isCopy;
     jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
-    ALOGD("copyData, isCopy=%d", isCopy);
+    ALOGV("copyData, isCopy=%d", isCopy);
     if (dst == nullptr) {
         jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
         return -1;
@@ -4249,7 +4219,7 @@
 
     long realSize = dvrClient->writeToBuffer(reinterpret_cast<signed char*>(dst) + offset, size);
     env->ReleaseByteArrayElements(buffer, dst, 0);
-    return (jlong) realSize;
+    return (jlong)realSize;
 }
 
 static sp<MediaEvent> getMediaEventSp(JNIEnv *env, jobject mediaEventObj) {
@@ -4259,9 +4229,9 @@
 static jobject android_media_tv_Tuner_media_event_get_linear_block(
         JNIEnv* env, jobject mediaEventObj) {
     sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
-    if (mediaEventSp == NULL) {
+    if (mediaEventSp == nullptr) {
         ALOGD("Failed get MediaEvent");
-        return NULL;
+        return nullptr;
     }
     android::Mutex::Autolock autoLock(mediaEventSp->mLock);
 
@@ -4271,9 +4241,9 @@
 static jobject android_media_tv_Tuner_media_event_get_audio_handle(
         JNIEnv* env, jobject mediaEventObj) {
     sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
-    if (mediaEventSp == NULL) {
+    if (mediaEventSp == nullptr) {
         ALOGD("Failed get MediaEvent");
-        return NULL;
+        return nullptr;
     }
 
     android::Mutex::Autolock autoLock(mediaEventSp->mLock);
@@ -4287,7 +4257,7 @@
 
 static void android_media_tv_Tuner_media_event_finalize(JNIEnv* env, jobject mediaEventObj) {
     sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
-    if (mediaEventSp == NULL) {
+    if (mediaEventSp == nullptr) {
         ALOGD("Failed get MediaEvent");
         return;
     }
@@ -4307,6 +4277,8 @@
             (void *)android_media_tv_Tuner_get_frontend_ids },
     { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
             (void *)android_media_tv_Tuner_open_frontend_by_handle },
+    { "nativeShareFrontend", "(I)I",
+            (void *)android_media_tv_Tuner_share_frontend },
     { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I",
             (void *)android_media_tv_Tuner_tune },
     { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune },
@@ -4494,19 +4466,18 @@
     return true;
 }
 
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
-    JNIEnv* env = NULL;
+jint JNI_OnLoad(JavaVM *vm, void * /* reserved */) {
+    JNIEnv *env = nullptr;
     jint result = -1;
 
     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed\n");
+        ALOGE("ERROR: GetEnv failed");
         return result;
     }
-    assert(env != NULL);
+    assert(env != nullptr);
 
     if (!register_android_media_tv_Tuner(env)) {
-        ALOGE("ERROR: Tuner native registration failed\n");
+        ALOGE("ERROR: Tuner native registration failed");
         return result;
     }
     return JNI_VERSION_1_4;
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 2a933b2..02c347f 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -17,18 +17,35 @@
 #ifndef _ANDROID_MEDIA_TV_TUNER_H_
 #define _ANDROID_MEDIA_TV_TUNER_H_
 
-#include <android/hardware/tv/tuner/1.1/types.h>
-
 #include <C2BlockInternal.h>
 #include <C2HandleIonInternal.h>
 #include <C2ParamDef.h>
-#include <fmq/MessageQueue.h>
-#include <fstream>
-#include <string>
-#include <unordered_map>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterMonitorEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterStatus.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxPid.h>
+#include <aidl/android/hardware/tv/tuner/DvrType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendCapabilities.h>
+#include <aidl/android/hardware/tv/tuner/FrontendEventType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendInfo.h>
+#include <aidl/android/hardware/tv/tuner/FrontendScanMessage.h>
+#include <aidl/android/hardware/tv/tuner/FrontendScanMessageType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendScanType.h>
+#include <aidl/android/hardware/tv/tuner/FrontendSettings.h>
+#include <aidl/android/hardware/tv/tuner/LnbEventType.h>
+#include <aidl/android/hardware/tv/tuner/PlaybackStatus.h>
+#include <aidl/android/hardware/tv/tuner/RecordStatus.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
+#include <fmq/AidlMessageQueue.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 
+#include <fstream>
+#include <string>
+#include <unordered_map>
+
+#include "jni.h"
 #include "tuner/DemuxClient.h"
 #include "tuner/DescramblerClient.h"
 #include "tuner/FilterClient.h"
@@ -39,48 +56,36 @@
 #include "tuner/LnbClientCallback.h"
 #include "tuner/TimeFilterClient.h"
 #include "tuner/TunerClient.h"
-#include "jni.h"
 
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMonitorEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxPid;
+using ::aidl::android::hardware::tv::tuner::DvrType;
+using ::aidl::android::hardware::tv::tuner::FrontendCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendEventType;
+using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessage;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanType;
+using ::aidl::android::hardware::tv::tuner::FrontendSettings;
+using ::aidl::android::hardware::tv::tuner::LnbEventType;
+using ::aidl::android::hardware::tv::tuner::PlaybackStatus;
+using ::aidl::android::hardware::tv::tuner::RecordStatus;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::android::hardware::EventFlag;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxPid;
-using ::android::hardware::tv::tuner::V1_0::DvrType;
-using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
-using ::android::hardware::tv::tuner::V1_0::FrontendId;
-using ::android::hardware::tv::tuner::V1_0::FrontendInfo;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
-using ::android::hardware::tv::tuner::V1_0::FrontendSettings;
-using ::android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_0::LnbEventType;
-using ::android::hardware::tv::tuner::V1_0::LnbId;
-using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
-using ::android::hardware::tv::tuner::V1_0::RecordStatus;
-using ::android::hardware::tv::tuner::V1_0::Result;
-using ::android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
-using ::android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEvent;
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageTypeExt1_1;
 
-using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-const static int TUNER_VERSION_1_1 = ((1 << 16) | 1);
+using MQ = MQDescriptor<int8_t, SynchronizedReadWrite>;
 
 namespace android {
 
 struct LnbClientCallbackImpl : public LnbClientCallback {
     ~LnbClientCallbackImpl();
     virtual void onEvent(LnbEventType lnbEventType);
-    virtual void onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+    virtual void onDiseqcMessage(const vector<uint8_t>& diseqcMessage);
 
     void setLnb(jweak lnbObj);
 private:
@@ -98,8 +103,8 @@
 };
 
 struct MediaEvent : public RefBase {
-    MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle, uint64_t dataId,
-        uint64_t dataSize, jobject obj);
+    MediaEvent(sp<FilterClient> filterClient, native_handle_t* avHandle, uint64_t dataId,
+               uint64_t dataSize, jobject obj);
     ~MediaEvent();
     jobject getLinearBlock();
     uint64_t getAudioHandle();
@@ -121,39 +126,24 @@
 
 struct FilterClientCallbackImpl : public FilterClientCallback {
     ~FilterClientCallbackImpl();
-    virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
-            const DemuxFilterEventExt& filterEventExt);
-    virtual void onFilterEvent(const DemuxFilterEvent& filterEvent);
+    virtual void onFilterEvent(const vector<DemuxFilterEvent>& events);
     virtual void onFilterStatus(const DemuxFilterStatus status);
 
     void setFilter(jweak filterObj, sp<FilterClient> filterClient);
 private:
     jweak mFilterObj;
     sp<FilterClient> mFilterClient;
-    jobjectArray getSectionEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getMediaEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getPesEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getTsRecordEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>&events,
-                    const std::vector<DemuxFilterEventExt::Event>& eventsExt);
-    jobjectArray getMmtpRecordEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>&events,
-                    const std::vector<DemuxFilterEventExt::Event>& eventsExt);
-    jobjectArray getDownloadEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getIpPayloadEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getTemiEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
-    jobjectArray getScramblingStatusEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt);
-    jobjectArray getIpCidChangeEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt);
-    jobjectArray getRestartEvent(
-            jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt);
+    void getSectionEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getMediaEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getPesEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getTsRecordEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getMmtpRecordEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getDownloadEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getIpPayloadEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getTemiEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getScramblingStatusEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getIpCidChangeEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
+    void getRestartEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event);
 };
 
 struct FrontendClientCallbackImpl : public FrontendClientCallback {
@@ -162,8 +152,6 @@
     virtual void onEvent(FrontendEventType frontendEventType);
     virtual void onScanMessage(
             FrontendScanMessageType type, const FrontendScanMessage& message);
-    virtual void onScanMessageExt1_1(
-            FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& messageExt);
 
     jweak mObject;
 };
@@ -179,12 +167,12 @@
     int unlinkCiCam(jint id);
     jobject getFrontendIds();
     jobject openFrontendByHandle(int feHandle);
+    int shareFrontend(int feId);
     jint closeFrontendById(int id);
     jobject getFrontendInfo(int id);
-    int tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
+    int tune(const FrontendSettings& settings);
     int stopTune();
-    int scan(const FrontendSettings& settings, FrontendScanType scanType,
-            const FrontendSettingsExt1_1& settingsExt1_1);
+    int scan(const FrontendSettings& settings, FrontendScanType scanType);
     int stopScan();
     int setLnb(sp<LnbClient> lnbClient);
     int setLna(bool enable);
@@ -210,20 +198,19 @@
     static sp<TunerClient> mTunerClient;
     sp<FrontendClient> mFeClient;
     int mFeId;
+    int mSharedFeId;
     sp<LnbClient> mLnbClient;
     sp<DemuxClient> mDemuxClient;
-    static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
-    static jobject getDtmbFrontendCaps(JNIEnv *env, int id);
-
-    bool isV1_1ExtendedStatusType(jint type);
+    static jobject getAnalogFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getAtsc3FrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getAtscFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getDvbcFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getDvbsFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getDvbtFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getIsdbs3FrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getIsdbsFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getIsdbtFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
+    static jobject getDtmbFrontendCaps(JNIEnv* env, FrontendCapabilities& caps);
 };
 
 class C2DataIdInfo : public C2Param {
diff --git a/media/jni/tuner/ClientHelper.h b/media/jni/tuner/ClientHelper.h
index 508dccf..d7a847a 100644
--- a/media/jni/tuner/ClientHelper.h
+++ b/media/jni/tuner/ClientHelper.h
@@ -17,22 +17,18 @@
 #ifndef _ANDROID_MEDIA_TV_CLIENT_HELPER_H_
 #define _ANDROID_MEDIA_TV_CLIENT_HELPER_H_
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <android/binder_parcel_utils.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
 #include <utils/Log.h>
 
+using ::aidl::android::hardware::tv::tuner::Result;
 using Status = ::ndk::ScopedAStatus;
 
-using ::android::hardware::tv::tuner::V1_0::Result;
-
-using namespace std;
-
 namespace android {
 
-struct ClientHelper {
-
+class ClientHelper {
 public:
-	static Result getServiceSpecificErrorCode(Status& s) {
+    static Result getServiceSpecificErrorCode(Status& s) {
         if (s.getExceptionCode() == EX_SERVICE_SPECIFIC) {
             return static_cast<Result>(s.getServiceSpecificError());
         } else if (s.isOk()) {
@@ -42,6 +38,7 @@
         return Result::UNKNOWN_ERROR;
     }
 };
+
 }  // namespace android
 
-#endif  // _ANDROID_MEDIA_TV_CLIENT_HELPER_H_
\ No newline at end of file
+#endif // _ANDROID_MEDIA_TV_CLIENT_HELPER_H_
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index 78cb5b0..4ee3f48 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,295 +16,156 @@
 
 #define LOG_TAG "DemuxClient"
 
+#include "DemuxClient.h"
+
+#include <aidl/android/hardware/tv/tuner/Constant.h>
+#include <aidl/android/hardware/tv/tuner/Constant64Bit.h>
 #include <android-base/logging.h>
 #include <utils/Log.h>
 
-#include "DemuxClient.h"
-
-using ::aidl::android::media::tv::tuner::TunerFrontendSettings;
-
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
-using ::android::hardware::tv::tuner::V1_0::Result;
+using ::aidl::android::hardware::tv::tuner::Constant;
+using ::aidl::android::hardware::tv::tuner::Constant64Bit;
 
 namespace android {
-
 /////////////// DemuxClient ///////////////////////
-
 DemuxClient::DemuxClient(shared_ptr<ITunerDemux> tunerDemux) {
     mTunerDemux = tunerDemux;
-    mId = -1;
 }
 
 DemuxClient::~DemuxClient() {
-    mTunerDemux = NULL;
-    mDemux = NULL;
-    mId = -1;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-void DemuxClient::setHidlDemux(sp<IDemux> demux) {
-    mDemux = demux;
+    mTunerDemux = nullptr;
 }
 
 Result DemuxClient::setFrontendDataSource(sp<FrontendClient> frontendClient) {
-    if (mTunerDemux != NULL) {
-        Status s = mTunerDemux->setFrontendDataSource(frontendClient->getAidlFrontend());
-        return ClientHelper::getServiceSpecificErrorCode(s);
+    if (frontendClient == nullptr) {
+        return Result::INVALID_ARGUMENT;
     }
 
-    if (mDemux != NULL) {
-        Result res = mDemux->setFrontendDataSource(frontendClient->getId());
-        return res;
+    if (mTunerDemux != nullptr) {
+        Status s = mTunerDemux->setFrontendDataSource(frontendClient->getAidlFrontend());
+        return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
     return Result::INVALID_STATE;
 }
 
-sp<FilterClient> DemuxClient::openFilter(DemuxFilterType type, int bufferSize,
-        sp<FilterClientCallback> cb) {
-    if (mTunerDemux != NULL) {
+Result DemuxClient::setFrontendDataSourceById(int frontendId) {
+    if (mTunerDemux != nullptr) {
+        Status s = mTunerDemux->setFrontendDataSourceById(frontendId);
+        return ClientHelper::getServiceSpecificErrorCode(s);
+    }
+
+    return Result::INVALID_STATE;
+}
+
+sp<FilterClient> DemuxClient::openFilter(const DemuxFilterType& type, int32_t bufferSize,
+                                         sp<FilterClientCallback> cb) {
+    if (cb == nullptr) {
+        return nullptr;
+    }
+
+    if (mTunerDemux != nullptr) {
         shared_ptr<ITunerFilter> tunerFilter;
         shared_ptr<TunerFilterCallback> callback =
                 ::ndk::SharedRefBase::make<TunerFilterCallback>(cb);
-        Status s = mTunerDemux->openFilter((int)type.mainType, getSubType(type),
-                    bufferSize, callback, &tunerFilter);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        Status s = mTunerDemux->openFilter(type, bufferSize, callback, &tunerFilter);
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new FilterClient(type, tunerFilter);
     }
 
-    if (mDemux != NULL) {
-        sp<HidlFilterCallback> callback = new HidlFilterCallback(cb);
-        sp<IFilter> hidlFilter = openHidlFilter(type, bufferSize, callback);
-        if (hidlFilter != NULL) {
-            sp<FilterClient> filterClient = new FilterClient(type, NULL);
-            filterClient->setHidlFilter(hidlFilter);
-            return filterClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
 sp<TimeFilterClient> DemuxClient::openTimeFilter() {
-    if (mTunerDemux != NULL) {
+    if (mTunerDemux != nullptr) {
         shared_ptr<ITunerTimeFilter> tunerTimeFilter;
         Status s = mTunerDemux->openTimeFilter(&tunerTimeFilter);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new TimeFilterClient(tunerTimeFilter);
     }
 
-    if (mDemux != NULL) {
-        sp<ITimeFilter> hidlTimeFilter = openHidlTimeFilter();
-        if (hidlTimeFilter != NULL) {
-            sp<TimeFilterClient> timeFilterClient = new TimeFilterClient(NULL);
-            timeFilterClient->setHidlTimeFilter(hidlTimeFilter);
-            return timeFilterClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-int DemuxClient::getAvSyncHwId(sp<FilterClient> filterClient) {
-    if (mTunerDemux != NULL) {
-        int hwId;
+int32_t DemuxClient::getAvSyncHwId(sp<FilterClient> filterClient) {
+    if (filterClient == nullptr) {
+        return static_cast<int32_t>(Constant::INVALID_AV_SYNC_ID);
+    }
+
+    if (mTunerDemux != nullptr) {
+        int32_t hwId;
         Status s = mTunerDemux->getAvSyncHwId(filterClient->getAidlFilter(), &hwId);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return INVALID_AV_SYNC_HW_ID;
+        if (!s.isOk()) {
+            return static_cast<int32_t>(Constant::INVALID_AV_SYNC_ID);
         }
         return hwId;
     }
 
-    if (mDemux != NULL) {
-        uint32_t avSyncHwId;
-        Result res;
-        sp<IFilter> halFilter = filterClient->getHalFilter();
-        mDemux->getAvSyncHwId(halFilter,
-                [&](Result r, uint32_t id) {
-                    res = r;
-                    avSyncHwId = id;
-                });
-        if (res == Result::SUCCESS) {
-            return (int) avSyncHwId;
-        }
-    }
-
-    return INVALID_AV_SYNC_HW_ID;
+    return static_cast<int32_t>(Constant::INVALID_AV_SYNC_ID);
 }
 
-long DemuxClient::getAvSyncTime(int avSyncHwId) {
-    if (mTunerDemux != NULL) {
+int64_t DemuxClient::getAvSyncTime(int32_t avSyncHwId) {
+    if (mTunerDemux != nullptr) {
         int64_t time;
         Status s = mTunerDemux->getAvSyncTime(avSyncHwId, &time);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return INVALID_AV_SYNC_TIME;
+        if (!s.isOk()) {
+            return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
         }
         return time;
     }
 
-    if (mDemux != NULL) {
-        uint64_t time;
-        Result res;
-        mDemux->getAvSyncTime(static_cast<uint32_t>(avSyncHwId),
-                [&](Result r, uint64_t ts) {
-                    res = r;
-                    time = ts;
-                });
-        if (res == Result::SUCCESS) {
-            return (long) time;
-        }
-    }
-
-    return INVALID_AV_SYNC_TIME;
+    return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
 }
 
-sp<DvrClient> DemuxClient::openDvr(DvrType dvbType, int bufferSize, sp<DvrClientCallback> cb) {
-    if (mTunerDemux != NULL) {
+sp<DvrClient> DemuxClient::openDvr(DvrType dvbType, int32_t bufferSize, sp<DvrClientCallback> cb) {
+    if (cb == nullptr) {
+        return nullptr;
+    }
+
+    if (mTunerDemux != nullptr) {
         shared_ptr<ITunerDvr> tunerDvr;
         shared_ptr<TunerDvrCallback> callback =
                 ::ndk::SharedRefBase::make<TunerDvrCallback>(cb);
-        Status s = mTunerDemux->openDvr((int)dvbType, bufferSize, callback, &tunerDvr);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        Status s = mTunerDemux->openDvr(dvbType, bufferSize, callback, &tunerDvr);
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new DvrClient(tunerDvr);
     }
 
-    if (mDemux != NULL) {
-        sp<HidlDvrCallback> callback = new HidlDvrCallback(cb);
-        sp<IDvr> hidlDvr = openHidlDvr(dvbType, bufferSize, callback);
-        if (hidlDvr != NULL) {
-            sp<DvrClient> dvrClient = new DvrClient(NULL);
-            dvrClient->setHidlDvr(hidlDvr);
-            return dvrClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-Result DemuxClient::connectCiCam(int ciCamId) {
-    if (mTunerDemux != NULL) {
+Result DemuxClient::connectCiCam(int32_t ciCamId) {
+    if (mTunerDemux != nullptr) {
         Status s = mTunerDemux->connectCiCam(ciCamId);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDemux != NULL) {
-        return mDemux->connectCiCam(static_cast<uint32_t>(ciCamId));
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DemuxClient::disconnectCiCam() {
-    if (mTunerDemux != NULL) {
+    if (mTunerDemux != nullptr) {
         Status s = mTunerDemux->disconnectCiCam();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDemux != NULL) {
-        return mDemux->disconnectCiCam();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DemuxClient::close() {
-    if (mTunerDemux != NULL) {
+    if (mTunerDemux != nullptr) {
         Status s = mTunerDemux->close();
-        mTunerDemux = NULL;
+        mTunerDemux = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDemux != NULL) {
-        Result res = mDemux->close();
-        mDemux = NULL;
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// DemuxClient Helper Methods ///////////////////////
-
-sp<IFilter> DemuxClient::openHidlFilter(DemuxFilterType type, int bufferSize,
-        sp<HidlFilterCallback> callback) {
-    if (mDemux == NULL) {
-        return NULL;
-    }
-
-    sp<IFilter> hidlFilter;
-    Result res;
-    mDemux->openFilter(type, bufferSize, callback,
-            [&](Result r, const sp<IFilter>& filter) {
-                hidlFilter = filter;
-                res = r;
-            });
-    if (res != Result::SUCCESS || hidlFilter == NULL) {
-        return NULL;
-    }
-
-    return hidlFilter;
-}
-
-sp<ITimeFilter> DemuxClient::openHidlTimeFilter() {
-    if (mDemux == NULL) {
-        return NULL;
-    }
-
-    sp<ITimeFilter> timeFilter;
-    Result res;
-    mDemux->openTimeFilter(
-            [&](Result r, const sp<ITimeFilter>& timeFilterSp) {
-                timeFilter = timeFilterSp;
-                res = r;
-            });
-
-    if (res != Result::SUCCESS || timeFilter == NULL) {
-        return NULL;
-    }
-
-    return timeFilter;
-}
-
-sp<IDvr> DemuxClient::openHidlDvr(DvrType dvrType, int bufferSize,
-        sp<HidlDvrCallback> callback) {
-    if (mDemux == NULL) {
-        return NULL;
-    }
-
-    sp<IDvr> hidlDvr;
-    Result res;
-    mDemux->openDvr(dvrType, bufferSize, callback,
-            [&](Result r, const sp<IDvr>& dvr) {
-                hidlDvr = dvr;
-                res = r;
-            });
-    if (res != Result::SUCCESS || hidlDvr == NULL) {
-        return NULL;
-    }
-
-    return hidlDvr;
-}
-
-int DemuxClient::getSubType(DemuxFilterType filterType) {
-    switch (filterType.mainType) {
-        case DemuxFilterMainType::TS:
-            return (int)filterType.subType.tsFilterType();
-        case DemuxFilterMainType::MMTP:
-            return (int)filterType.subType.mmtpFilterType();
-        case DemuxFilterMainType::IP:
-            return (int)filterType.subType.ipFilterType();
-        case DemuxFilterMainType::TLV:
-            return (int)filterType.subType.tlvFilterType();
-        case DemuxFilterMainType::ALP:
-            return (int)filterType.subType.alpFilterType();
-        default:
-            return -1;
-    }
-}
 }  // namespace android
diff --git a/media/jni/tuner/DemuxClient.h b/media/jni/tuner/DemuxClient.h
index c38a8fa..d5f5f2f 100644
--- a/media/jni/tuner/DemuxClient.h
+++ b/media/jni/tuner/DemuxClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,12 +17,11 @@
 #ifndef _ANDROID_MEDIA_TV_DEMUX_CLIENT_H_
 #define _ANDROID_MEDIA_TV_DEMUX_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidl/android/media/tv/tuner/ITunerDemux.h>
-#include <android/hardware/tv/tuner/1.0/IDemux.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
 
-#include "DvrClient.h"
 #include "ClientHelper.h"
+#include "DvrClient.h"
 #include "DvrClientCallback.h"
 #include "FilterClient.h"
 #include "FilterClientCallback.h"
@@ -30,20 +29,14 @@
 #include "TimeFilterClient.h"
 
 using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterType;
+using ::aidl::android::hardware::tv::tuner::DvrType;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::ITunerDemux;
 using ::aidl::android::media::tv::tuner::ITunerTimeFilter;
 
-using ::android::hardware::tv::tuner::V1_0::IDemux;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using ::android::hardware::tv::tuner::V1_0::DvrType;
-using ::android::hardware::tv::tuner::V1_0::IDemux;
-using ::android::hardware::tv::tuner::V1_0::ITimeFilter;
-
 using namespace std;
 
-const int64_t INVALID_AV_SYNC_TIME = -1;
-const int INVALID_AV_SYNC_HW_ID = -1;
-
 namespace android {
 
 struct DemuxClient : public RefBase {
@@ -52,18 +45,21 @@
     DemuxClient(shared_ptr<ITunerDemux> tunerDemux);
     ~DemuxClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlDemux(sp<IDemux> demux);
-
     /**
      * Set a frontend resource as data input of the demux.
      */
     Result setFrontendDataSource(sp<FrontendClient> frontendClient);
 
     /**
+     * Set a frontend resource by handle as data input of the demux.
+     */
+    Result setFrontendDataSourceById(int frontendId);
+
+    /**
      * Open a new filter client.
      */
-    sp<FilterClient> openFilter(DemuxFilterType type, int bufferSize, sp<FilterClientCallback> cb);
+    sp<FilterClient> openFilter(const DemuxFilterType& type, int32_t bufferSize,
+                                sp<FilterClientCallback> cb);
 
     /**
      * Open time filter of the demux.
@@ -73,22 +69,22 @@
     /**
      * Get hardware sync ID for audio and video.
      */
-    int getAvSyncHwId(sp<FilterClient> filterClient);
+    int32_t getAvSyncHwId(sp<FilterClient> filterClient);
 
     /**
      * Get current time stamp to use for A/V sync.
      */
-    long getAvSyncTime(int avSyncHwId);
+    int64_t getAvSyncTime(int32_t avSyncHwId);
 
     /**
      * Open a DVR (Digital Video Record) client.
      */
-    sp<DvrClient> openDvr(DvrType dvbType, int bufferSize, sp<DvrClientCallback> cb);
+    sp<DvrClient> openDvr(DvrType dvbType, int32_t bufferSize, sp<DvrClientCallback> cb);
 
     /**
      * Connect Conditional Access Modules (CAM) through Common Interface (CI).
      */
-    Result connectCiCam(int ciCamId);
+    Result connectCiCam(int32_t ciCamId);
 
     /**
      * Disconnect Conditional Access Modules (CAM).
@@ -105,29 +101,12 @@
      */
     shared_ptr<ITunerDemux> getAidlDemux() { return mTunerDemux; }
 
-    void setId(int id) { mId = id; }
-    int getId() { return mId; }
-
 private:
-    sp<IFilter> openHidlFilter(DemuxFilterType type, int bufferSize, sp<HidlFilterCallback> cb);
-    sp<ITimeFilter> openHidlTimeFilter();
-    sp<IDvr> openHidlDvr(DvrType type, int bufferSize, sp<HidlDvrCallback> cb);
-    int getSubType(DemuxFilterType filterType);
-
     /**
      * An AIDL Tuner Demux Singleton assigned at the first time the Tuner Client
      * opens a demux. Default null when demux is not opened.
      */
     shared_ptr<ITunerDemux> mTunerDemux;
-
-    /**
-     * A Demux HAL interface that is ready before migrating to the TunerDemux.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<IDemux> mDemux;
-
-    int mId;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/DescramblerClient.cpp b/media/jni/tuner/DescramblerClient.cpp
index 3e4ed82..052fa7a 100644
--- a/media/jni/tuner/DescramblerClient.cpp
+++ b/media/jni/tuner/DescramblerClient.cpp
@@ -21,118 +21,69 @@
 
 #include "DescramblerClient.h"
 
-using ::android::hardware::tv::tuner::V1_0::Result;
-
 namespace android {
 
 /////////////// DescramblerClient ///////////////////////
-
 DescramblerClient::DescramblerClient(shared_ptr<ITunerDescrambler> tunerDescrambler) {
     mTunerDescrambler = tunerDescrambler;
 }
 
 DescramblerClient::~DescramblerClient() {
-    mTunerDescrambler = NULL;
-    mDescrambler = NULL;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-void DescramblerClient::setHidlDescrambler(sp<IDescrambler> descrambler) {
-    mDescrambler = descrambler;
+    mTunerDescrambler = nullptr;
 }
 
 Result DescramblerClient::setDemuxSource(sp<DemuxClient> demuxClient) {
-    if (demuxClient == NULL) {
+    if (demuxClient == nullptr) {
         return Result::INVALID_ARGUMENT;
     }
 
-    if (mTunerDescrambler != NULL) {
+    if (mTunerDescrambler != nullptr) {
         Status s = mTunerDescrambler->setDemuxSource(demuxClient->getAidlDemux());
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDescrambler != NULL) {
-        return mDescrambler->setDemuxSource(demuxClient->getId());
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DescramblerClient::setKeyToken(vector<uint8_t> keyToken) {
-    if (mTunerDescrambler != NULL) {
+    if (mTunerDescrambler != nullptr) {
         Status s = mTunerDescrambler->setKeyToken(keyToken);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDescrambler != NULL) {
-        return mDescrambler->setKeyToken(keyToken);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DescramblerClient::addPid(DemuxPid pid, sp<FilterClient> optionalSourceFilter) {
-    if (mTunerDescrambler != NULL) {
-        shared_ptr<ITunerFilter> aidlFilter = (optionalSourceFilter == NULL)
-                ? NULL : optionalSourceFilter->getAidlFilter();
-        Status s = mTunerDescrambler->addPid(getAidlDemuxPid(pid), aidlFilter);
+    if (mTunerDescrambler != nullptr) {
+        shared_ptr<ITunerFilter> aidlFilter =
+                (optionalSourceFilter == nullptr) ? nullptr : optionalSourceFilter->getAidlFilter();
+        Status s = mTunerDescrambler->addPid(pid, aidlFilter);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDescrambler != NULL) {
-        sp<IFilter> halFilter = (optionalSourceFilter == NULL)
-                ? NULL : optionalSourceFilter->getHalFilter();
-        return mDescrambler->addPid(pid, halFilter);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DescramblerClient::removePid(DemuxPid pid, sp<FilterClient> optionalSourceFilter) {
-    if (mTunerDescrambler != NULL) {
-        shared_ptr<ITunerFilter> aidlFilter = (optionalSourceFilter == NULL)
-                ? NULL : optionalSourceFilter->getAidlFilter();
-        Status s = mTunerDescrambler->removePid(getAidlDemuxPid(pid), aidlFilter);
+    if (mTunerDescrambler != nullptr) {
+        shared_ptr<ITunerFilter> aidlFilter =
+                (optionalSourceFilter == nullptr) ? nullptr : optionalSourceFilter->getAidlFilter();
+        Status s = mTunerDescrambler->removePid(pid, aidlFilter);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDescrambler != NULL) {
-        sp<IFilter> halFilter = (optionalSourceFilter == NULL)
-                ? NULL : optionalSourceFilter->getHalFilter();
-        return mDescrambler->removePid(pid, halFilter);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DescramblerClient::close() {
-    if (mTunerDescrambler != NULL) {
+    if (mTunerDescrambler != nullptr) {
         Status s = mTunerDescrambler->close();
-        mTunerDescrambler = NULL;
+        mTunerDescrambler = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDescrambler != NULL) {
-        Result res = mDescrambler->close();
-        mDescrambler = NULL;
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// DescramblerClient Helper Methods ///////////////////////
-
-TunerDemuxPid DescramblerClient::getAidlDemuxPid(DemuxPid& pid) {
-    TunerDemuxPid aidlPid;
-    switch (pid.getDiscriminator()) {
-        case DemuxPid::hidl_discriminator::tPid:
-            aidlPid.set<TunerDemuxPid::tPid>((int)pid.tPid());
-            break;
-        case DemuxPid::hidl_discriminator::mmtpPid:
-            aidlPid.set<TunerDemuxPid::mmtpPid>((int)pid.mmtpPid());
-            break;
-    }
-    return aidlPid;
-}
 }  // namespace android
diff --git a/media/jni/tuner/DescramblerClient.h b/media/jni/tuner/DescramblerClient.h
index a8fa1e2..c851e84 100644
--- a/media/jni/tuner/DescramblerClient.h
+++ b/media/jni/tuner/DescramblerClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,19 +17,15 @@
 #ifndef _ANDROID_MEDIA_TV_DESCRAMBLER_CLIENT_H_
 #define _ANDROID_MEDIA_TV_DESCRAMBLER_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidl/android/media/tv/tuner/ITunerDescrambler.h>
-#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
 
 #include "DemuxClient.h"
 #include "FilterClient.h"
 
+using ::aidl::android::hardware::tv::tuner::DemuxPid;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::ITunerDescrambler;
-using ::aidl::android::media::tv::tuner::TunerDemuxPid;
-
-using ::android::hardware::tv::tuner::V1_0::IDescrambler;
-using ::android::hardware::tv::tuner::V1_0::Result;
-using ::android::hardware::tv::tuner::V1_0::DemuxPid;
 
 using namespace std;
 
@@ -41,9 +37,6 @@
     DescramblerClient(shared_ptr<ITunerDescrambler> tunerDescrambler);
     ~DescramblerClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlDescrambler(sp<IDescrambler> descrambler);
-
      /**
      * Set a demux as source of the descrambler.
      */
@@ -70,20 +63,11 @@
     Result close();
 
 private:
-    TunerDemuxPid getAidlDemuxPid(DemuxPid& pid);
-
     /**
      * An AIDL Tuner Descrambler Singleton assigned at the first time the Tuner Client
      * opens a descrambler. Default null when descrambler is not opened.
      */
     shared_ptr<ITunerDescrambler> mTunerDescrambler;
-
-    /**
-     * A Descrambler HAL interface that is ready before migrating to the TunerDescrambler.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<IDescrambler> mDescrambler;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/DvrClient.cpp b/media/jni/tuner/DvrClient.cpp
index 0476216..052b465 100644
--- a/media/jni/tuner/DvrClient.cpp
+++ b/media/jni/tuner/DvrClient.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,48 +14,42 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "DvrClient"
 
+#include "DvrClient.h"
+
+#include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
 #include <android-base/logging.h>
-#include <fmq/ConvertMQDescriptors.h>
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include "ClientHelper.h"
-#include "DvrClient.h"
 
-using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
-using ::android::hardware::tv::tuner::V1_0::Result;
+using ::aidl::android::hardware::tv::tuner::DemuxQueueNotifyBits;
 
 namespace android {
-
 /////////////// DvrClient ///////////////////////
-
 DvrClient::DvrClient(shared_ptr<ITunerDvr> tunerDvr) {
     mTunerDvr = tunerDvr;
     mFd = -1;
-    mDvrMQ = NULL;
-    mDvrMQEventFlag = NULL;
+    mDvrMQ = nullptr;
+    mDvrMQEventFlag = nullptr;
 }
 
 DvrClient::~DvrClient() {
-    mTunerDvr = NULL;
-    mDvr = NULL;
+    mTunerDvr = nullptr;
     mFd = -1;
-    mDvrMQ = NULL;
-    mDvrMQEventFlag = NULL;
+    mDvrMQ = nullptr;
+    mDvrMQEventFlag = nullptr;
 }
 
-// TODO: remove after migration to Tuner Service is done.
-void DvrClient::setHidlDvr(sp<IDvr> dvr) {
-    mDvr = dvr;
-}
-
-void DvrClient::setFd(int fd) {
+void DvrClient::setFd(int32_t fd) {
     mFd = fd;
 }
 
-long DvrClient::readFromFile(long size) {
-    if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+int64_t DvrClient::readFromFile(int64_t size) {
+    if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
         ALOGE("Failed to readFromFile. DVR mq is not configured");
         return -1;
     }
@@ -64,16 +58,16 @@
         return -1;
     }
 
-    long available = mDvrMQ->availableToWrite();
-    long write = min(size, available);
+    int64_t available = mDvrMQ->availableToWrite();
+    int64_t write = min(size, available);
 
     AidlMQ::MemTransaction tx;
-    long ret = 0;
+    int64_t ret = 0;
     if (mDvrMQ->beginWrite(write, &tx)) {
         auto first = tx.getFirstRegion();
         auto data = first.getAddress();
-        long length = first.getLength();
-        long firstToWrite = min(length, write);
+        int64_t length = first.getLength();
+        int64_t firstToWrite = min(length, write);
         ret = read(mFd, data, firstToWrite);
 
         if (ret < 0) {
@@ -81,17 +75,20 @@
             return -1;
         }
         if (ret < firstToWrite) {
-            ALOGW("file to MQ, first region: %ld bytes to write, but %ld bytes written",
-                    firstToWrite, ret);
+            ALOGW("file to MQ, first region: %" PRIu64 " bytes to write, but %" PRIu64
+                  " bytes written",
+                  firstToWrite, ret);
         } else if (firstToWrite < write) {
-            ALOGD("write second region: %ld bytes written, %ld bytes in total", ret, write);
+            ALOGV("write second region: %" PRIu64 " bytes written, %" PRIu64 " bytes in total", ret,
+                  write);
             auto second = tx.getSecondRegion();
             data = second.getAddress();
             length = second.getLength();
-            int secondToWrite = std::min(length, write - firstToWrite);
+            int64_t secondToWrite = std::min(length, write - firstToWrite);
             ret += read(mFd, data, secondToWrite);
         }
-        ALOGD("file to MQ: %ld bytes need to be written, %ld bytes written", write, ret);
+        ALOGV("file to MQ: %" PRIu64 " bytes need to be written, %" PRIu64 " bytes written", write,
+              ret);
         if (!mDvrMQ->commitWrite(ret)) {
             ALOGE("Error: failed to commit write!");
             return -1;
@@ -106,8 +103,8 @@
     return ret;
 }
 
-long DvrClient::readFromBuffer(int8_t* buffer, long size) {
-    if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+int64_t DvrClient::readFromBuffer(int8_t* buffer, int64_t size) {
+    if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
         ALOGE("Failed to readFromBuffer. DVR mq is not configured");
         return -1;
     }
@@ -116,7 +113,7 @@
         return -1;
     }
 
-    long available = mDvrMQ->availableToWrite();
+    int64_t available = mDvrMQ->availableToWrite();
     size = min(size, available);
 
     if (mDvrMQ->write(buffer, size)) {
@@ -128,8 +125,8 @@
     return size;
 }
 
-long DvrClient::writeToFile(long size) {
-    if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+int64_t DvrClient::writeToFile(int64_t size) {
+    if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
         ALOGE("Failed to writeToFile. DVR mq is not configured");
         return -1;
     }
@@ -138,16 +135,16 @@
         return -1;
     }
 
-    long available = mDvrMQ->availableToRead();
-    long toRead = min(size, available);
+    int64_t available = mDvrMQ->availableToRead();
+    int64_t toRead = min(size, available);
 
-    long ret = 0;
+    int64_t ret = 0;
     AidlMQ::MemTransaction tx;
     if (mDvrMQ->beginRead(toRead, &tx)) {
         auto first = tx.getFirstRegion();
         auto data = first.getAddress();
-        long length = first.getLength();
-        long firstToRead = std::min(length, toRead);
+        int64_t length = first.getLength();
+        int64_t firstToRead = std::min(length, toRead);
         ret = write(mFd, data, firstToRead);
 
         if (ret < 0) {
@@ -155,16 +152,18 @@
             return -1;
         }
         if (ret < firstToRead) {
-            ALOGW("MQ to file: %ld bytes read, but %ld bytes written", firstToRead, ret);
+            ALOGW("MQ to file: %" PRIu64 " bytes read, but %" PRIu64 " bytes written", firstToRead,
+                  ret);
         } else if (firstToRead < toRead) {
-            ALOGD("read second region: %ld bytes read, %ld bytes in total", ret, toRead);
+            ALOGV("read second region: %" PRIu64 " bytes read, %" PRIu64 " bytes in total", ret,
+                  toRead);
             auto second = tx.getSecondRegion();
             data = second.getAddress();
             length = second.getLength();
-            int secondToRead = toRead - firstToRead;
+            int32_t secondToRead = toRead - firstToRead;
             ret += write(mFd, data, secondToRead);
         }
-        ALOGD("MQ to file: %ld bytes to be read, %ld bytes written", toRead, ret);
+        ALOGV("MQ to file: %" PRIu64 " bytes to be read, %" PRIu64 " bytes written", toRead, ret);
         if (!mDvrMQ->commitRead(ret)) {
             ALOGE("Error: failed to commit read!");
             return 0;
@@ -179,8 +178,8 @@
     return ret;
 }
 
-long DvrClient::writeToBuffer(int8_t* buffer, long size) {
-    if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+int64_t DvrClient::writeToBuffer(int8_t* buffer, int64_t size) {
+    if (mDvrMQ == nullptr || mDvrMQEventFlag == nullptr) {
         ALOGE("Failed to writetoBuffer. DVR mq is not configured");
         return -1;
     }
@@ -189,7 +188,7 @@
         return -1;
     }
 
-    long available = mDvrMQ->availableToRead();
+    int64_t available = mDvrMQ->availableToRead();
     size = min(size, available);
 
     if (mDvrMQ->read(buffer, size)) {
@@ -202,9 +201,8 @@
 }
 
 Result DvrClient::configure(DvrSettings settings) {
-    if (mTunerDvr != NULL) {
-        TunerDvrSettings dvrSettings = getAidlDvrSettingsFromHidl(settings);
-        Status s = mTunerDvr->configure(dvrSettings);
+    if (mTunerDvr != nullptr) {
+        Status s = mTunerDvr->configure(settings);
         Result res = ClientHelper::getServiceSpecificErrorCode(s);
         if (res != Result::SUCCESS) {
             return res;
@@ -221,196 +219,95 @@
         return res;
     }
 
-    if (mDvr != NULL) {
-        Result res = mDvr->configure(settings);
-        if (res == Result::SUCCESS) {
-            MQDescriptorSync<uint8_t> dvrMQDesc;
-            res = getQueueDesc(dvrMQDesc);
-            if (res == Result::SUCCESS) {
-                AidlMQDesc aidlMQDesc;
-                unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
-                        dvrMQDesc,  &aidlMQDesc);
-                mDvrMQ = new (nothrow) AidlMessageQueue(aidlMQDesc);
-                EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
-            }
-        }
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::attachFilter(sp<FilterClient> filterClient) {
-    if (mTunerDvr != NULL) {
-        Status s = mTunerDvr->attachFilter(filterClient->getAidlFilter());
-        return ClientHelper::getServiceSpecificErrorCode(s);
+    if (filterClient == nullptr) {
+        return Result::INVALID_ARGUMENT;
     }
 
-    if (mDvr != NULL) {
-        sp<IFilter> hidlFilter = filterClient->getHalFilter();
-        if (hidlFilter == NULL) {
-            return Result::INVALID_ARGUMENT;
-        }
-        return mDvr->attachFilter(hidlFilter);
+    if (mTunerDvr != nullptr) {
+        Status s = mTunerDvr->attachFilter(filterClient->getAidlFilter());
+        return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::detachFilter(sp<FilterClient> filterClient) {
-    if (mTunerDvr != NULL) {
-        Status s = mTunerDvr->detachFilter(filterClient->getAidlFilter());
-        return ClientHelper::getServiceSpecificErrorCode(s);
+    if (filterClient == nullptr) {
+        return Result::INVALID_ARGUMENT;
     }
 
-    if (mDvr != NULL) {
-        sp<IFilter> hidlFilter = filterClient->getHalFilter();
-        if (hidlFilter == NULL) {
-            return Result::INVALID_ARGUMENT;
-        }
-        return mDvr->detachFilter(hidlFilter);
+    if (mTunerDvr != nullptr) {
+        Status s = mTunerDvr->detachFilter(filterClient->getAidlFilter());
+        return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::start() {
-    if (mTunerDvr != NULL) {
+    if (mTunerDvr != nullptr) {
         Status s = mTunerDvr->start();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDvr != NULL) {
-        return mDvr->start();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::stop() {
-    if (mTunerDvr != NULL) {
+    if (mTunerDvr != nullptr) {
         Status s = mTunerDvr->stop();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDvr != NULL) {
-        return mDvr->stop();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::flush() {
-    if (mTunerDvr != NULL) {
+    if (mTunerDvr != nullptr) {
         Status s = mTunerDvr->flush();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDvr != NULL) {
-        return mDvr->flush();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result DvrClient::close() {
-    if (mDvrMQEventFlag != NULL) {
+    if (mDvrMQEventFlag != nullptr) {
         EventFlag::deleteEventFlag(&mDvrMQEventFlag);
     }
-    mDvrMQ = NULL;
+    mDvrMQ = nullptr;
 
-    if (mTunerDvr != NULL) {
+    if (mTunerDvr != nullptr) {
         Status s = mTunerDvr->close();
-        mTunerDvr = NULL;
+        mTunerDvr = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mDvr != NULL) {
-        Result res = mDvr->close();
-        mDvr = NULL;
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// IDvrCallback ///////////////////////
-
-HidlDvrCallback::HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback)
-        : mDvrClientCallback(dvrClientCallback) {}
-
-Return<void> HidlDvrCallback::onRecordStatus(const RecordStatus status) {
-    if (mDvrClientCallback != NULL) {
-        mDvrClientCallback->onRecordStatus(status);
-    }
-    return Void();
-}
-
-Return<void> HidlDvrCallback::onPlaybackStatus(const PlaybackStatus status) {
-    if (mDvrClientCallback != NULL) {
-        mDvrClientCallback->onPlaybackStatus(status);
-    }
-    return Void();
-}
-
 /////////////// TunerDvrCallback ///////////////////////
-
 TunerDvrCallback::TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback)
         : mDvrClientCallback(dvrClientCallback) {}
 
-Status TunerDvrCallback::onRecordStatus(int status) {
-    if (mDvrClientCallback != NULL) {
-        mDvrClientCallback->onRecordStatus(static_cast<RecordStatus>(status));
+Status TunerDvrCallback::onRecordStatus(RecordStatus status) {
+    if (mDvrClientCallback != nullptr) {
+        mDvrClientCallback->onRecordStatus(status);
         return Status::ok();
     }
     return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
-Status TunerDvrCallback::onPlaybackStatus(int status) {
-    if (mDvrClientCallback != NULL) {
-        mDvrClientCallback->onPlaybackStatus(static_cast<PlaybackStatus>(status));
+Status TunerDvrCallback::onPlaybackStatus(PlaybackStatus status) {
+    if (mDvrClientCallback != nullptr) {
+        mDvrClientCallback->onPlaybackStatus(status);
         return Status::ok();
     }
     return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
-/////////////// DvrClient Helper Methods ///////////////////////
-
-Result DvrClient::getQueueDesc(MQDesc& dvrMQDesc) {
-    if (mDvr != NULL) {
-        Result res = Result::UNKNOWN_ERROR;
-        mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
-            dvrMQDesc = desc;
-            res = r;
-        });
-        return res;
-    }
-
-    return Result::INVALID_STATE;
-}
-
-TunerDvrSettings DvrClient::getAidlDvrSettingsFromHidl(DvrSettings settings) {
-    TunerDvrSettings s;
-    switch (settings.getDiscriminator()) {
-        case DvrSettings::hidl_discriminator::record: {
-            s.statusMask = static_cast<int>(settings.record().statusMask);
-            s.lowThreshold = static_cast<int>(settings.record().lowThreshold);
-            s.highThreshold = static_cast<int>(settings.record().highThreshold);
-            s.dataFormat = static_cast<int>(settings.record().dataFormat);
-            s.packetSize = static_cast<int>(settings.record().packetSize);
-            return s;
-        }
-        case DvrSettings::hidl_discriminator::playback: {
-            s.statusMask = static_cast<int>(settings.playback().statusMask);
-            s.lowThreshold = static_cast<int>(settings.playback().lowThreshold);
-            s.highThreshold = static_cast<int>(settings.playback().highThreshold);
-            s.dataFormat = static_cast<int>(settings.playback().dataFormat);
-            s.packetSize = static_cast<int>(settings.playback().packetSize);
-            return s;
-        }
-        default:
-            break;
-    }
-    return s;
-}
 }  // namespace android
diff --git a/media/jni/tuner/DvrClient.h b/media/jni/tuner/DvrClient.h
index 252554e..9080c72 100644
--- a/media/jni/tuner/DvrClient.h
+++ b/media/jni/tuner/DvrClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,36 +17,29 @@
 #ifndef _ANDROID_MEDIA_TV_DVR_CLIENT_H_
 #define _ANDROID_MEDIA_TV_DVR_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/DvrSettings.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidl/android/media/tv/tuner/BnTunerDvrCallback.h>
 #include <aidl/android/media/tv/tuner/ITunerDvr.h>
-#include <android/hardware/tv/tuner/1.0/IDvr.h>
-#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
 #include <fmq/AidlMessageQueue.h>
-#include <fmq/MessageQueue.h>
 
 #include "DvrClientCallback.h"
 #include "FilterClient.h"
 
 using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
 using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::tv::tuner::DvrSettings;
+using ::aidl::android::hardware::tv::tuner::PlaybackStatus;
+using ::aidl::android::hardware::tv::tuner::RecordStatus;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::BnTunerDvrCallback;
 using ::aidl::android::media::tv::tuner::ITunerDvr;
-using ::aidl::android::media::tv::tuner::TunerDvrSettings;
-
-using ::android::hardware::EventFlag;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::tv::tuner::V1_0::DvrSettings;
-using ::android::hardware::tv::tuner::V1_0::IDvr;
-using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
 
 using namespace std;
 
 namespace android {
 
-using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-using MQDesc = MQDescriptorSync<uint8_t>;
 using AidlMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
 
@@ -55,19 +48,8 @@
 public:
     TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback);
 
-    Status onRecordStatus(int status);
-    Status onPlaybackStatus(int status);
-
-private:
-    sp<DvrClientCallback> mDvrClientCallback;
-};
-
-struct HidlDvrCallback : public IDvrCallback {
-
-public:
-    HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback);
-    virtual Return<void> onRecordStatus(const RecordStatus status);
-    virtual Return<void> onPlaybackStatus(const PlaybackStatus status);
+    Status onRecordStatus(RecordStatus status);
+    Status onPlaybackStatus(PlaybackStatus status);
 
 private:
     sp<DvrClientCallback> mDvrClientCallback;
@@ -79,33 +61,30 @@
     DvrClient(shared_ptr<ITunerDvr> tunerDvr);
     ~DvrClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlDvr(sp<IDvr> dvr);
-
     /**
      * Set the DVR file descriptor.
      */
-    void setFd(int fd);
+    void setFd(int32_t fd);
 
     /**
      * Read data from file with given size. Return the actual read size.
      */
-    long readFromFile(long size);
+    int64_t readFromFile(int64_t size);
 
     /**
      * Read data from the given buffer with given size. Return the actual read size.
      */
-    long readFromBuffer(int8_t* buffer, long size);
+    int64_t readFromBuffer(int8_t* buffer, int64_t size);
 
     /**
      * Write data to file with given size. Return the actual write size.
      */
-    long writeToFile(long size);
+    int64_t writeToFile(int64_t size);
 
     /**
      * Write data to the given buffer with given size. Return the actual write size.
      */
-    long writeToBuffer(int8_t* buffer, long size);
+    int64_t writeToBuffer(int8_t* buffer, int64_t size);
 
     /**
      * Configure the DVR.
@@ -143,26 +122,16 @@
     Result close();
 
 private:
-    Result getQueueDesc(MQDesc& dvrMQDesc);
-    TunerDvrSettings getAidlDvrSettingsFromHidl(DvrSettings settings);
-
     /**
      * An AIDL Tuner Dvr Singleton assigned at the first time the Tuner Client
      * opens a dvr. Default null when dvr is not opened.
      */
     shared_ptr<ITunerDvr> mTunerDvr;
 
-    /**
-     * A Dvr HAL interface that is ready before migrating to the TunerDvr.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<IDvr> mDvr;
-
     AidlMQ* mDvrMQ;
     EventFlag* mDvrMQEventFlag;
     string mFilePath;
-    int mFd;
+    int32_t mFd;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/DvrClientCallback.h b/media/jni/tuner/DvrClientCallback.h
index 6684424..a75f199 100644
--- a/media/jni/tuner/DvrClientCallback.h
+++ b/media/jni/tuner/DvrClientCallback.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,8 +17,12 @@
 #ifndef _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
 #define _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
 
-using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
-using ::android::hardware::tv::tuner::V1_0::RecordStatus;
+#include <aidl/android/hardware/tv/tuner/PlaybackStatus.h>
+#include <aidl/android/hardware/tv/tuner/RecordStatus.h>
+#include <utils/RefBase.h>
+
+using ::aidl::android::hardware::tv::tuner::PlaybackStatus;
+using ::aidl::android::hardware::tv::tuner::RecordStatus;
 
 using namespace std;
 
@@ -30,4 +34,4 @@
 };
 }  // namespace android
 
-#endif  // _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
\ No newline at end of file
+#endif // _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index 324c09a..eea27ea 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,65 +16,43 @@
 
 #define LOG_TAG "FilterClient"
 
-#include <aidlcommonsupport/NativeHandle.h>
-#include <android-base/logging.h>
-#include <fmq/ConvertMQDescriptors.h>
-#include <utils/Log.h>
-
 #include "FilterClient.h"
 
-using ::aidl::android::media::tv::tuner::TunerDemuxIpAddressSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterAlpConfiguration;
-using ::aidl::android::media::tv::tuner::TunerFilterIpConfiguration;
-using ::aidl::android::media::tv::tuner::TunerFilterMmtpConfiguration;
-using ::aidl::android::media::tv::tuner::TunerFilterMonitorEvent;
-using ::aidl::android::media::tv::tuner::TunerFilterScIndexMask;
-using ::aidl::android::media::tv::tuner::TunerFilterSectionBits;
-using ::aidl::android::media::tv::tuner::TunerFilterSectionCondition;
-using ::aidl::android::media::tv::tuner::TunerFilterSectionTableInfo;
-using ::aidl::android::media::tv::tuner::TunerFilterSharedHandleInfo;
-using ::aidl::android::media::tv::tuner::TunerFilterTlvConfiguration;
-using ::aidl::android::media::tv::tuner::TunerFilterTsConfiguration;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
-using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
-using ::android::hardware::tv::tuner::V1_0::DemuxStreamId;
-using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
-using ::android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEvent;
-using ::android::hardware::tv::tuner::V1_1::ScramblingStatus;
+#include <aidl/android/hardware/tv/tuner/DemuxFilterMainType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMainType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxQueueNotifyBits;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterType;
+using ::aidl::android::hardware::tv::tuner::ScramblingStatus;
 
 namespace android {
-
 /////////////// FilterClient ///////////////////////
-
 FilterClient::FilterClient(DemuxFilterType type, shared_ptr<ITunerFilter> tunerFilter) {
     mTunerFilter = tunerFilter;
-    mAvSharedHandle = NULL;
+    mAvSharedHandle = nullptr;
     checkIsMediaFilter(type);
 }
 
 FilterClient::~FilterClient() {
-    mTunerFilter = NULL;
-    mFilter = NULL;
-    mFilter_1_1 = NULL;
-    mAvSharedHandle = NULL;
+    mTunerFilter = nullptr;
+    mAvSharedHandle = nullptr;
     mAvSharedMemSize = 0;
     mIsMediaFilter = false;
     mIsPassthroughFilter = false;
-    mFilterMQ = NULL;
-    mFilterMQEventFlag = NULL;
+    mFilterMQ = nullptr;
+    mFilterMQEventFlag = nullptr;
 }
 
-// TODO: remove after migration to Tuner Service is done.
-void FilterClient::setHidlFilter(sp<IFilter> filter) {
-    mFilter = filter;
-    mFilter_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
-}
-
-int FilterClient::read(int8_t* buffer, int size) {
+int64_t FilterClient::read(int8_t* buffer, int64_t size) {
     Result res = getFilterMq();
     if (res != Result::SUCCESS) {
         return -1;
@@ -85,8 +63,8 @@
 SharedHandleInfo FilterClient::getAvSharedHandleInfo() {
     handleAvShareMemory();
     SharedHandleInfo info{
-        .sharedHandle = (mIsMediaFilter && !mIsPassthroughFilter) ? mAvSharedHandle : NULL,
-        .size = mAvSharedMemSize,
+            .sharedHandle = (mIsMediaFilter && !mIsPassthroughFilter) ? mAvSharedHandle : nullptr,
+            .size = mAvSharedMemSize,
     };
 
     return info;
@@ -96,8 +74,8 @@
     Result res;
     checkIsPassthroughFilter(configure);
 
-    if (mTunerFilter != NULL) {
-        Status s = mTunerFilter->configure(getAidlFilterSettings(configure));
+    if (mTunerFilter != nullptr) {
+        Status s = mTunerFilter->configure(configure);
         res = ClientHelper::getServiceSpecificErrorCode(s);
         if (res == Result::SUCCESS) {
             getAvSharedHandleInfo();
@@ -105,171 +83,96 @@
         return res;
     }
 
-    if (mFilter != NULL) {
-        res = mFilter->configure(configure);
-        if (res == Result::SUCCESS) {
-            getAvSharedHandleInfo();
-        }
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-Result FilterClient::configureMonitorEvent(int monitorEventType) {
-    if (mTunerFilter != NULL) {
+Result FilterClient::configureMonitorEvent(int32_t monitorEventType) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->configureMonitorEvent(monitorEventType);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter_1_1 != NULL) {
-        return mFilter_1_1->configureMonitorEvent(monitorEventType);
-    }
-
     return Result::INVALID_STATE;
 }
 
-Result FilterClient::configureIpFilterContextId(int cid) {
-    if (mTunerFilter != NULL) {
+Result FilterClient::configureIpFilterContextId(int32_t cid) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->configureIpFilterContextId(cid);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter_1_1 != NULL) {
-        return mFilter_1_1->configureIpCid(cid);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::configureAvStreamType(AvStreamType avStreamType) {
-    if (mTunerFilter != NULL) {
-        int type;
-        switch (avStreamType.getDiscriminator()) {
-            case AvStreamType::hidl_discriminator::audio:
-                type = (int)avStreamType.audio();
-                break;
-            case AvStreamType::hidl_discriminator::video:
-                type = (int)avStreamType.video();
-                break;
-        }
-        Status s = mTunerFilter->configureAvStreamType(type);
+    if (mTunerFilter != nullptr) {
+        Status s = mTunerFilter->configureAvStreamType(avStreamType);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter_1_1 != NULL) {
-        return mFilter_1_1->configureAvStreamType(avStreamType);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::start() {
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->start();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        return mFilter->start();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::stop() {
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->stop();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        return mFilter->stop();
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::flush() {
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->flush();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        return mFilter->flush();
+    return Result::INVALID_STATE;
+}
+
+Result FilterClient::getId(int32_t& id) {
+    if (mTunerFilter != nullptr) {
+        Status s = mTunerFilter->getId(&id);
+        return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
     return Result::INVALID_STATE;
 }
 
-Result FilterClient::getId(uint32_t& id) {
-    if (mTunerFilter != NULL) {
-        int32_t id32Bit;
-        Status s = mTunerFilter->getId(&id32Bit);
-        id = static_cast<uint32_t>(id32Bit);
+Result FilterClient::getId64Bit(int64_t& id) {
+    if (mTunerFilter != nullptr) {
+        Status s = mTunerFilter->getId64Bit(&id);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        Result res;
-        mFilter->getId([&](Result r, uint32_t filterId) {
-            res = r;
-            id = filterId;
-        });
-        return res;
-    }
-
-    return Result::INVALID_STATE;
-}
-
-Result FilterClient::getId64Bit(uint64_t& id) {
-    if (mTunerFilter != NULL) {
-        int64_t id64Bit;
-        Status s = mTunerFilter->getId64Bit(&id64Bit);
-        id = static_cast<uint64_t>(id64Bit);
-        return ClientHelper::getServiceSpecificErrorCode(s);
-    }
-
-    if (mFilter_1_1 != NULL) {
-        Result res;
-        mFilter_1_1->getId64Bit([&](Result r, uint64_t filterId) {
-            res = r;
-            id = filterId;
-        });
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::releaseAvHandle(native_handle_t* handle, uint64_t avDataId) {
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->releaseAvHandle(makeToAidl(handle), avDataId);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        return mFilter->releaseAvHandle(hidl_handle(handle), avDataId);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FilterClient::setDataSource(sp<FilterClient> filterClient){
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->setDataSource(filterClient->getAidlFilter());
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        sp<IFilter> sourceFilter = filterClient->getHalFilter();
-        if (sourceFilter == NULL) {
-            return Result::INVALID_ARGUMENT;
-        }
-        return mFilter->setDataSource(sourceFilter);
-    }
-
     return Result::INVALID_STATE;
 }
 
@@ -277,648 +180,38 @@
     if (mFilterMQEventFlag) {
         EventFlag::deleteEventFlag(&mFilterMQEventFlag);
     }
-    mFilterMQEventFlag = NULL;
-    mFilterMQ = NULL;
+    mFilterMQEventFlag = nullptr;
+    mFilterMQ = nullptr;
 
-    if (mTunerFilter != NULL) {
+    if (mTunerFilter != nullptr) {
         Status s = mTunerFilter->close();
         closeAvSharedMemory();
-        mTunerFilter = NULL;
+        mTunerFilter = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFilter != NULL) {
-        Result res = mFilter->close();
-        mFilter = NULL;
-        mFilter_1_1 = NULL;
-        closeAvSharedMemory();
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// IFilterCallback ///////////////////////
-
-HidlFilterCallback::HidlFilterCallback(sp<FilterClientCallback> filterClientCallback)
-        : mFilterClientCallback(filterClientCallback) {}
-
-Return<void> HidlFilterCallback::onFilterStatus(const DemuxFilterStatus status) {
-    if (mFilterClientCallback != NULL) {
-        mFilterClientCallback->onFilterStatus(status);
-    }
-    return Void();
-}
-
-Return<void> HidlFilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
-    if (mFilterClientCallback != NULL) {
-        mFilterClientCallback->onFilterEvent(filterEvent);
-    }
-    return Void();
-}
-
-Return<void> HidlFilterCallback::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
-        const DemuxFilterEventExt& filterEventExt) {
-    if (mFilterClientCallback != NULL) {
-        mFilterClientCallback->onFilterEvent_1_1(filterEvent, filterEventExt);
-    }
-    return Void();
-}
-
 /////////////// TunerFilterCallback ///////////////////////
 
 TunerFilterCallback::TunerFilterCallback(sp<FilterClientCallback> filterClientCallback)
         : mFilterClientCallback(filterClientCallback) {}
 
-Status TunerFilterCallback::onFilterStatus(int status) {
-    if (mFilterClientCallback != NULL) {
-        mFilterClientCallback->onFilterStatus(static_cast<DemuxFilterStatus>(status));
+Status TunerFilterCallback::onFilterStatus(DemuxFilterStatus status) {
+    if (mFilterClientCallback != nullptr) {
+        mFilterClientCallback->onFilterStatus(status);
         return Status::ok();
     }
     return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
-Status TunerFilterCallback::onFilterEvent(const vector<TunerFilterEvent>& filterEvents) {
-    if (mFilterClientCallback == NULL) {
-        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
+Status TunerFilterCallback::onFilterEvent(const vector<DemuxFilterEvent>& filterEvents) {
+    if (mFilterClientCallback != nullptr) {
+        mFilterClientCallback->onFilterEvent(filterEvents);
+        return Status::ok();
     }
-
-    if (filterEvents.size() == 0) {
-        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_ARGUMENT));
-    }
-
-    DemuxFilterEvent event;
-    DemuxFilterEventExt eventExt;
-    getHidlFilterEvent(filterEvents, event, eventExt);
-    if (eventExt.events.size() > 0) {
-        mFilterClientCallback->onFilterEvent_1_1(event, eventExt);
-    } else {
-        mFilterClientCallback->onFilterEvent(event);
-    }
-
-    return Status::ok();
-}
-
-/////////////// FilterClient Helper Methods ///////////////////////
-
-TunerFilterConfiguration FilterClient::getAidlFilterSettings(DemuxFilterSettings configure) {
-    TunerFilterConfiguration config;
-    switch (configure.getDiscriminator()) {
-        case DemuxFilterSettings::hidl_discriminator::ts:
-            return getAidlTsSettings(configure.ts());
-        case DemuxFilterSettings::hidl_discriminator::mmtp:
-            return getAidlMmtpSettings(configure.mmtp());
-        case DemuxFilterSettings::hidl_discriminator::ip:
-            return getAidlIpSettings(configure.ip());
-        case DemuxFilterSettings::hidl_discriminator::tlv:
-            return getAidlTlvSettings(configure.tlv());
-        case DemuxFilterSettings::hidl_discriminator::alp:
-            return getAidlAlpSettings(configure.alp());
-        default:
-            break;
-    }
-    ALOGE("Wrong DemuxFilterSettings union.");
-    return config;
-}
-
-TunerFilterConfiguration FilterClient::getAidlTsSettings(DemuxTsFilterSettings ts) {
-    TunerFilterConfiguration config;
-    TunerFilterSettings filterSettings;
-    switch (ts.filterSettings.getDiscriminator()) {
-        case DemuxTsFilterSettings::FilterSettings::hidl_discriminator::av: {
-            filterSettings.set<TunerFilterSettings::av>(
-                    getAidlAvSettings(ts.filterSettings.av()));
-            break;
-        }
-        case DemuxTsFilterSettings::FilterSettings::hidl_discriminator::section: {
-            filterSettings.set<TunerFilterSettings::section>(
-                    getAidlSectionSettings(ts.filterSettings.section()));
-            break;
-        }
-        case DemuxTsFilterSettings::FilterSettings::hidl_discriminator::pesData: {
-            filterSettings.set<TunerFilterSettings::pesData>(
-                    getAidlPesDataSettings(ts.filterSettings.pesData()));
-            break;
-        }
-        case DemuxTsFilterSettings::FilterSettings::hidl_discriminator::record: {
-            filterSettings.set<TunerFilterSettings::record>(
-                    getAidlRecordSettings(ts.filterSettings.record()));
-            break;
-        }
-        default:
-            filterSettings.set<TunerFilterSettings::nothing>(true);
-            break;
-    }
-
-    TunerFilterTsConfiguration aidlTs{
-        .tpid = static_cast<char16_t>(ts.tpid),
-        .filterSettings = filterSettings,
-    };
-    config.set<TunerFilterConfiguration::ts>(aidlTs);
-
-    return config;
-}
-
-TunerFilterConfiguration FilterClient::getAidlMmtpSettings(DemuxMmtpFilterSettings mmtp) {
-    TunerFilterConfiguration config;
-    TunerFilterSettings filterSettings;
-    switch (mmtp.filterSettings.getDiscriminator()) {
-        case DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::av: {
-            filterSettings.set<TunerFilterSettings::av>(
-                    getAidlAvSettings(mmtp.filterSettings.av()));
-            break;
-        }
-        case DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::section: {
-            filterSettings.set<TunerFilterSettings::section>(
-                    getAidlSectionSettings(mmtp.filterSettings.section()));
-            break;
-        }
-        case DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::pesData: {
-            filterSettings.set<TunerFilterSettings::pesData>(
-                    getAidlPesDataSettings(mmtp.filterSettings.pesData()));
-            break;
-        }
-        case DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::record: {
-            filterSettings.set<TunerFilterSettings::record>(
-                    getAidlRecordSettings(mmtp.filterSettings.record()));
-            break;
-        }
-        case DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::download: {
-            filterSettings.set<TunerFilterSettings::download>(
-                    getAidlDownloadSettings(mmtp.filterSettings.download()));
-            break;
-        }
-        default:
-            filterSettings.set<TunerFilterSettings::nothing>(true);
-            break;
-    }
-
-    TunerFilterMmtpConfiguration aidlMmtp{
-        .mmtpPid = static_cast<char16_t>(mmtp.mmtpPid),
-        .filterSettings = filterSettings,
-    };
-    config.set<TunerFilterConfiguration::mmtp>(aidlMmtp);
-
-    return config;
-}
-
-TunerFilterConfiguration FilterClient::getAidlIpSettings(DemuxIpFilterSettings ip) {
-    TunerFilterConfiguration config;
-    TunerFilterSettings filterSettings;
-    switch (ip.filterSettings.getDiscriminator()) {
-        case DemuxIpFilterSettings::FilterSettings::hidl_discriminator::section: {
-            filterSettings.set<TunerFilterSettings::section>(
-                    getAidlSectionSettings(ip.filterSettings.section()));
-            break;
-        }
-        case DemuxIpFilterSettings::FilterSettings::hidl_discriminator::bPassthrough: {
-            filterSettings.set<TunerFilterSettings::isPassthrough>(
-                    ip.filterSettings.bPassthrough());
-            break;
-        }
-        default:
-            filterSettings.set<TunerFilterSettings::nothing>(true);
-            break;
-    }
-
-    TunerDemuxIpAddressSettings ipAddr{
-        .srcPort = static_cast<char16_t>(ip.ipAddr.srcPort),
-        .dstPort = static_cast<char16_t>(ip.ipAddr.dstPort),
-    };
-    getAidlIpAddress(ip.ipAddr, ipAddr.srcIpAddress, ipAddr.dstIpAddress);
-
-    TunerFilterIpConfiguration aidlIp{
-        .ipAddr = ipAddr,
-        .filterSettings = filterSettings,
-    };
-    config.set<TunerFilterConfiguration::ip>(aidlIp);
-
-    return config;
-}
-
-void FilterClient::getAidlIpAddress(DemuxIpAddress ipAddr,
-        TunerDemuxIpAddress& srcIpAddress, TunerDemuxIpAddress& dstIpAddress) {
-    switch (ipAddr.srcIpAddress.getDiscriminator()) {
-        case DemuxIpAddress::SrcIpAddress::hidl_discriminator::v4: {
-            int size = ipAddr.srcIpAddress.v4().size();
-            srcIpAddress.isIpV6 = false;
-            srcIpAddress.addr.resize(size);
-            copy(&ipAddr.srcIpAddress.v4()[0], &ipAddr.srcIpAddress.v4()[size],
-                    srcIpAddress.addr.begin());
-            break;
-        }
-        case DemuxIpAddress::SrcIpAddress::hidl_discriminator::v6: {
-            int size = ipAddr.srcIpAddress.v6().size();
-            srcIpAddress.isIpV6 = true;
-            srcIpAddress.addr.resize(size);
-            copy(&ipAddr.srcIpAddress.v6()[0], &ipAddr.srcIpAddress.v6()[size],
-                    srcIpAddress.addr.begin());
-            break;
-        }
-    }
-    switch (ipAddr.dstIpAddress.getDiscriminator()) {
-        case DemuxIpAddress::DstIpAddress::hidl_discriminator::v4: {
-            int size = ipAddr.dstIpAddress.v4().size();
-            dstIpAddress.isIpV6 = false;
-            dstIpAddress.addr.resize(size);
-            copy(&ipAddr.dstIpAddress.v4()[0], &ipAddr.dstIpAddress.v4()[size],
-                    dstIpAddress.addr.begin());
-            break;
-        }
-        case DemuxIpAddress::DstIpAddress::hidl_discriminator::v6: {
-            int size = ipAddr.dstIpAddress.v6().size();
-            dstIpAddress.isIpV6 = true;
-            dstIpAddress.addr.resize(size);
-            copy(&ipAddr.dstIpAddress.v6()[0], &ipAddr.dstIpAddress.v6()[size],
-                    dstIpAddress.addr.begin());
-            break;
-        }
-    }
-}
-
-TunerFilterConfiguration FilterClient::getAidlTlvSettings(DemuxTlvFilterSettings tlv) {
-    TunerFilterConfiguration config;
-    TunerFilterSettings filterSettings;
-    switch (tlv.filterSettings.getDiscriminator()) {
-        case DemuxTlvFilterSettings::FilterSettings::hidl_discriminator::section: {
-            filterSettings.set<TunerFilterSettings::section>(
-                    getAidlSectionSettings(tlv.filterSettings.section()));
-            break;
-        }
-        case DemuxTlvFilterSettings::FilterSettings::hidl_discriminator::bPassthrough: {
-            filterSettings.set<TunerFilterSettings::isPassthrough>(
-                    tlv.filterSettings.bPassthrough());
-            break;
-        }
-        default:
-            filterSettings.set<TunerFilterSettings::nothing>(true);
-            break;
-    }
-
-    TunerFilterTlvConfiguration aidlTlv{
-        .packetType = static_cast<int8_t>(tlv.packetType),
-        .isCompressedIpPacket = tlv.isCompressedIpPacket,
-        .filterSettings = filterSettings,
-    };
-    config.set<TunerFilterConfiguration::tlv>(aidlTlv);
-
-    return config;
-}
-
-TunerFilterConfiguration FilterClient::getAidlAlpSettings(DemuxAlpFilterSettings alp) {
-    TunerFilterConfiguration config;
-    TunerFilterSettings filterSettings;
-    switch (alp.filterSettings.getDiscriminator()) {
-        case DemuxAlpFilterSettings::FilterSettings::hidl_discriminator::section: {
-            filterSettings.set<TunerFilterSettings::section>(
-                    getAidlSectionSettings(alp.filterSettings.section()));
-            break;
-        }
-        default:
-            filterSettings.set<TunerFilterSettings::nothing>(true);
-            break;
-    }
-
-    TunerFilterAlpConfiguration aidlAlp{
-        .packetType = static_cast<int8_t>(alp.packetType),
-        .lengthType = static_cast<int8_t>(alp.lengthType),
-        .filterSettings = filterSettings,
-    };
-    config.set<TunerFilterConfiguration::alp>(aidlAlp);
-
-    return config;
-}
-
-TunerFilterAvSettings FilterClient::getAidlAvSettings(DemuxFilterAvSettings hidlAv) {
-    TunerFilterAvSettings aidlAv{
-        .isPassthrough = hidlAv.isPassthrough,
-    };
-    return aidlAv;
-}
-
-TunerFilterSectionSettings FilterClient::getAidlSectionSettings(
-        DemuxFilterSectionSettings hidlSection) {
-    TunerFilterSectionSettings aidlSection;
-
-    switch (hidlSection.condition.getDiscriminator()) {
-        case DemuxFilterSectionSettings::Condition::hidl_discriminator::sectionBits: {
-            TunerFilterSectionBits sectionBits;
-            auto hidlSectionBits = hidlSection.condition.sectionBits();
-            sectionBits.filter.resize(hidlSectionBits.filter.size());
-            sectionBits.mask.resize(hidlSectionBits.mask.size());
-            sectionBits.mode.resize(hidlSectionBits.mode.size());
-            copy(hidlSectionBits.filter.begin(), hidlSectionBits.filter.end(),
-                    sectionBits.filter.begin());
-            copy(hidlSectionBits.mask.begin(), hidlSectionBits.mask.end(),
-                    sectionBits.mask.begin());
-            copy(hidlSectionBits.mode.begin(), hidlSectionBits.mode.end(),
-                    sectionBits.mode.begin());
-            aidlSection.condition.set<TunerFilterSectionCondition::sectionBits>(sectionBits);
-            break;
-        }
-        case DemuxFilterSectionSettings::Condition::hidl_discriminator::tableInfo: {
-            TunerFilterSectionTableInfo tableInfo{
-                .tableId = static_cast<char16_t>(hidlSection.condition.tableInfo().tableId),
-                .version = static_cast<char16_t>(hidlSection.condition.tableInfo().version),
-            };
-            aidlSection.condition.set<TunerFilterSectionCondition::tableInfo>(tableInfo);
-            break;
-        }
-    }
-    aidlSection.isCheckCrc = hidlSection.isCheckCrc;
-    aidlSection.isRepeat = hidlSection.isRepeat;
-    aidlSection.isRaw = hidlSection.isRaw;
-    return aidlSection;
-}
-
-TunerFilterPesDataSettings FilterClient::getAidlPesDataSettings(
-        DemuxFilterPesDataSettings hidlPesData) {
-    TunerFilterPesDataSettings aidlPesData{
-        .streamId = static_cast<char16_t>(hidlPesData.streamId),
-        .isRaw = hidlPesData.isRaw,
-    };
-    return aidlPesData;
-}
-
-TunerFilterRecordSettings FilterClient::getAidlRecordSettings(
-        DemuxFilterRecordSettings hidlRecord) {
-    TunerFilterScIndexMask mask;
-    switch (hidlRecord.scIndexMask.getDiscriminator()) {
-        case DemuxFilterRecordSettings::ScIndexMask::hidl_discriminator::sc: {
-            mask.set<TunerFilterScIndexMask::sc>(hidlRecord.scIndexMask.sc());
-            break;
-        }
-        case DemuxFilterRecordSettings::ScIndexMask::hidl_discriminator::scHevc: {
-            mask.set<TunerFilterScIndexMask::scHevc>(hidlRecord.scIndexMask.scHevc());
-            break;
-        }
-        default:
-            break;
-    }
-    TunerFilterRecordSettings aidlRecord{
-        .tsIndexMask = static_cast<int32_t>(hidlRecord.tsIndexMask),
-        .scIndexType = static_cast<int32_t>(hidlRecord.scIndexType),
-        .scIndexMask = mask,
-    };
-    return aidlRecord;
-}
-
-TunerFilterDownloadSettings FilterClient::getAidlDownloadSettings(
-        DemuxFilterDownloadSettings hidlDownload) {
-    TunerFilterDownloadSettings aidlDownload{
-        .downloadId = static_cast<int32_t>(hidlDownload.downloadId),
-    };
-    return aidlDownload;
-}
-
-void TunerFilterCallback::getHidlFilterEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event, DemuxFilterEventExt& eventExt) {
-    switch (filterEvents[0].getTag()) {
-        case  TunerFilterEvent::media: {
-            getHidlMediaEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::section: {
-            getHidlSectionEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::pes: {
-            getHidlPesEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::tsRecord: {
-            getHidlTsRecordEvent(filterEvents, event, eventExt);
-            break;
-        }
-        case  TunerFilterEvent::mmtpRecord: {
-            getHidlMmtpRecordEvent(filterEvents, event, eventExt);
-            break;
-        }
-        case  TunerFilterEvent::download: {
-            getHidlDownloadEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::ipPayload: {
-            getHidlIpPayloadEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::temi: {
-            getHidlTemiEvent(filterEvents, event);
-            break;
-        }
-        case  TunerFilterEvent::monitor: {
-            getHidlMonitorEvent(filterEvents, eventExt);
-            break;
-        }
-        case  TunerFilterEvent::startId: {
-            getHidlRestartEvent(filterEvents, eventExt);
-            break;
-        }
-    }
-}
-
-void TunerFilterCallback::getHidlMediaEvent(
-        const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        hidl_handle handle = hidl_handle(makeFromAidl(filterEvents[i]
-                .get<TunerFilterEvent::media>().avMemory));
-        event.events[i].media({
-            .avMemory = handle,
-            .streamId = static_cast<DemuxStreamId>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().streamId),
-            .isPtsPresent = filterEvents[i]
-                    .get<TunerFilterEvent::media>().isPtsPresent,
-            .pts = static_cast<uint64_t>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().pts),
-            .dataLength = static_cast<uint32_t>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().dataLength),
-            .offset = static_cast<uint32_t>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().offset),
-            .isSecureMemory = filterEvents[i]
-                    .get<TunerFilterEvent::media>().isSecureMemory,
-            .avDataId = static_cast<uint64_t>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().avDataId),
-            .mpuSequenceNumber = static_cast<uint32_t>(filterEvents[i]
-                    .get<TunerFilterEvent::media>().offset),
-            .isPesPrivateData = filterEvents[i]
-                    .get<TunerFilterEvent::media>().isPesPrivateData,
-        });
-
-        if (filterEvents[i].get<TunerFilterEvent::media>().isAudioExtraMetaData) {
-            event.events[i].media().extraMetaData.audio({
-                .adFade = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.adFade),
-                .adPan = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.adPan),
-                .versionTextTag = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.versionTextTag),
-                .adGainCenter = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.adGainCenter),
-                .adGainFront = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.adGainFront),
-                .adGainSurround = static_cast<uint8_t>(filterEvents[i]
-                        .get<TunerFilterEvent::media>().audio.adGainSurround),
-            });
-        } else {
-            event.events[i].media().extraMetaData.noinit();
-        }
-    }
-}
-
-void TunerFilterCallback::getHidlSectionEvent(
-        const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto section = filterEvents[i].get<TunerFilterEvent::section>();
-        event.events[i].section({
-            .tableId = static_cast<uint16_t>(section.tableId),
-            .version = static_cast<uint16_t>(section.version),
-            .sectionNum = static_cast<uint16_t>(section.sectionNum),
-            .dataLength = static_cast<uint16_t>(section.dataLength),
-        });
-    }
-}
-
-void TunerFilterCallback::getHidlPesEvent(
-        const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto pes = filterEvents[i].get<TunerFilterEvent::pes>();
-        event.events[i].pes({
-            .streamId = static_cast<DemuxStreamId>(pes.streamId),
-            .dataLength = static_cast<uint16_t>(pes.dataLength),
-            .mpuSequenceNumber = static_cast<uint32_t>(pes.mpuSequenceNumber),
-        });
-    }
-}
-
-void TunerFilterCallback::getHidlTsRecordEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event, DemuxFilterEventExt& eventExt) {
-    event.events.resize(filterEvents.size());
-    eventExt.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto ts = filterEvents[i].get<TunerFilterEvent::tsRecord>();
-        event.events[i].tsRecord({
-            .tsIndexMask = static_cast<uint32_t>(ts.tsIndexMask),
-            .byteNumber = static_cast<uint64_t>(ts.byteNumber),
-        });
-        event.events[i].tsRecord().pid.tPid(static_cast<DemuxTpid>(ts.pid));
-
-        switch (ts.scIndexMask.getTag()) {
-            case TunerFilterScIndexMask::sc: {
-                event.events[i].tsRecord().scIndexMask.sc(
-                        ts.scIndexMask.get<TunerFilterScIndexMask::sc>());
-                break;
-            }
-            case TunerFilterScIndexMask::scHevc: {
-                event.events[i].tsRecord().scIndexMask.scHevc(
-                        ts.scIndexMask.get<TunerFilterScIndexMask::scHevc>());
-                break;
-            }
-            default:
-                break;
-        }
-
-        if (ts.isExtended) {
-            eventExt.events[i].tsRecord({
-                .pts = static_cast<uint64_t>(ts.pts),
-                .firstMbInSlice = static_cast<uint32_t>(ts.firstMbInSlice),
-            });
-        } else {
-            eventExt.events[i].noinit();
-        }
-    }
-}
-
-void TunerFilterCallback::getHidlMmtpRecordEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event, DemuxFilterEventExt& eventExt) {
-    event.events.resize(filterEvents.size());
-    eventExt.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto mmtp = filterEvents[i].get<TunerFilterEvent::mmtpRecord>();
-        event.events[i].mmtpRecord({
-            .scHevcIndexMask = static_cast<uint32_t>(mmtp.scHevcIndexMask),
-            .byteNumber = static_cast<uint64_t>(mmtp.byteNumber),
-        });
-
-        if (mmtp.isExtended) {
-            eventExt.events[i].mmtpRecord({
-                .pts = static_cast<uint64_t>(mmtp.pts),
-                .mpuSequenceNumber = static_cast<uint32_t>(mmtp.mpuSequenceNumber),
-                .firstMbInSlice = static_cast<uint32_t>(mmtp.firstMbInSlice),
-                .tsIndexMask = static_cast<uint32_t>(mmtp.tsIndexMask),
-            });
-        } else {
-            eventExt.events[i].noinit();
-        }
-    }
-}
-
-void TunerFilterCallback::getHidlDownloadEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto download = filterEvents[i].get<TunerFilterEvent::download>();
-        event.events[i].download({
-            .itemId = static_cast<uint32_t>(download.itemId),
-            .mpuSequenceNumber = static_cast<uint32_t>(download.mpuSequenceNumber),
-            .itemFragmentIndex = static_cast<uint32_t>(download.itemFragmentIndex),
-            .lastItemFragmentIndex = static_cast<uint32_t>(download.lastItemFragmentIndex),
-            .dataLength = static_cast<uint16_t>(download.dataLength),
-        });
-    }
-}
-
-void TunerFilterCallback::getHidlIpPayloadEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto ip = filterEvents[i].get<TunerFilterEvent::ipPayload>();
-        event.events[i].ipPayload({
-            .dataLength = static_cast<uint16_t>(ip.dataLength),
-        });
-    }
-}
-
-void TunerFilterCallback::getHidlTemiEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEvent& event) {
-    event.events.resize(filterEvents.size());
-    for (int i = 0; i < filterEvents.size(); i++) {
-        auto temi = filterEvents[i].get<TunerFilterEvent::temi>();
-        event.events[i].temi({
-            .pts = static_cast<uint64_t>(temi.pts),
-            .descrTag = static_cast<uint8_t>(temi.descrTag),
-        });
-        hidl_vec<uint8_t> descrData(temi.descrData.begin(), temi.descrData.end());
-        event.events[i].temi().descrData = descrData;
-    }
-}
-
-void TunerFilterCallback::getHidlMonitorEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEventExt& eventExt) {
-    auto monitor = filterEvents[0].get<TunerFilterEvent::monitor>();
-    eventExt.events.resize(1);
-    DemuxFilterMonitorEvent monitorEvent;
-    switch (monitor.getTag()) {
-        case TunerFilterMonitorEvent::scramblingStatus: {
-            monitorEvent.scramblingStatus(static_cast<ScramblingStatus>(monitor.scramblingStatus));
-            eventExt.events[0].monitorEvent(monitorEvent);
-            break;
-        }
-        case TunerFilterMonitorEvent::cid: {
-            monitorEvent.cid(static_cast<uint32_t>(monitor.cid));
-            eventExt.events[0].monitorEvent(monitorEvent);
-            break;
-        }
-    }
-}
-
-void TunerFilterCallback::getHidlRestartEvent(const vector<TunerFilterEvent>& filterEvents,
-        DemuxFilterEventExt& eventExt) {
-    uint32_t startId = filterEvents[0].get<TunerFilterEvent::startId>();
-    eventExt.events.resize(1);
-    eventExt.events[0].startId(static_cast<uint32_t>(startId));
+    return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
 Result FilterClient::getFilterMq() {
@@ -931,39 +224,21 @@
 
     if (mTunerFilter != NULL) {
         Status s = mTunerFilter->getQueueDesc(&aidlMqDesc);
-        res = ClientHelper::getServiceSpecificErrorCode(s);
-        if (res == Result::SUCCESS) {
+        if (s.isOk()) {
             mFilterMQ = new (nothrow) AidlMQ(aidlMqDesc, false/*resetPointer*/);
             EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag);
         }
-        return res;
-    }
-
-    if (mFilter != NULL) {
-        MQDescriptorSync<uint8_t> filterMQDesc;
-        mFilter->getQueueDesc(
-                [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
-                    filterMQDesc = desc;
-                    res = r;
-                });
-        if (res == Result::SUCCESS) {
-            AidlMQDesc aidlMQDesc;
-            unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
-                    filterMQDesc,  &aidlMQDesc);
-            mFilterMQ = new (nothrow) AidlMessageQueue(aidlMQDesc, false/*resetPointer*/);
-            EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag);
-        }
     }
 
     return res;
 }
 
-int FilterClient::copyData(int8_t* buffer, int size) {
-    if (mFilterMQ == NULL || mFilterMQEventFlag == NULL) {
+int64_t FilterClient::copyData(int8_t* buffer, int64_t size) {
+    if (mFilterMQ == nullptr || mFilterMQEventFlag == nullptr) {
         return -1;
     }
 
-    int available = mFilterMQ->availableToRead();
+    int64_t available = mFilterMQ->availableToRead();
     size = min(size, available);
 
     if (mFilterMQ->read(buffer, size)) {
@@ -977,16 +252,18 @@
 
 void FilterClient::checkIsMediaFilter(DemuxFilterType type) {
     if (type.mainType == DemuxFilterMainType::MMTP) {
-        if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
-                type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+        if (type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>() ==
+                    DemuxMmtpFilterType::AUDIO ||
+            type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>() ==
+                    DemuxMmtpFilterType::VIDEO) {
             mIsMediaFilter = true;
             return;
         }
     }
 
     if (type.mainType == DemuxFilterMainType::TS) {
-        if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
-                type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+        if (type.subType.get<DemuxFilterSubType::Tag::tsFilterType>() == DemuxTsFilterType::AUDIO ||
+            type.subType.get<DemuxFilterSubType::Tag::tsFilterType>() == DemuxTsFilterType::VIDEO) {
             mIsMediaFilter = true;
             return;
         }
@@ -1001,15 +278,19 @@
         return;
     }
 
-    if (configure.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::ts) {
-        if (configure.ts().filterSettings.av().isPassthrough) {
+    if (configure.getTag() == DemuxFilterSettings::Tag::ts) {
+        if (configure.get<DemuxFilterSettings::Tag::ts>()
+                    .filterSettings.get<DemuxTsFilterSettingsFilterSettings::Tag::av>()
+                    .isPassthrough) {
             mIsPassthroughFilter = true;
             return;
         }
     }
 
-    if (configure.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::mmtp) {
-        if (configure.mmtp().filterSettings.av().isPassthrough) {
+    if (configure.getTag() == DemuxFilterSettings::Tag::mmtp) {
+        if (configure.get<DemuxFilterSettings::Tag::mmtp>()
+                    .filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::Tag::av>()
+                    .isPassthrough) {
             mIsPassthroughFilter = true;
             return;
         }
@@ -1019,37 +300,28 @@
 }
 
 void FilterClient::handleAvShareMemory() {
-    if (mAvSharedHandle != NULL) {
+    if (mAvSharedHandle != nullptr) {
         return;
     }
-    if (mTunerFilter != NULL && mIsMediaFilter && !mIsPassthroughFilter) {
-        TunerFilterSharedHandleInfo aidlHandleInfo;
-        Status s = mTunerFilter->getAvSharedHandleInfo(&aidlHandleInfo);
-        if (ClientHelper::getServiceSpecificErrorCode(s) == Result::SUCCESS) {
-            mAvSharedHandle = native_handle_clone(makeFromAidl(aidlHandleInfo.handle));
-            mAvSharedMemSize = aidlHandleInfo.size;
+    if (mTunerFilter != nullptr && mIsMediaFilter && !mIsPassthroughFilter) {
+        int64_t size;
+        NativeHandle avMemory;
+        Status s = mTunerFilter->getAvSharedHandle(&avMemory, &size);
+        if (s.isOk()) {
+            mAvSharedHandle = native_handle_clone(makeFromAidl(avMemory));
+            mAvSharedMemSize = size;
         }
-        return;
-    }
-
-    if (mFilter_1_1 != NULL && mIsMediaFilter && !mIsPassthroughFilter) {
-        mFilter_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
-            if (r == Result::SUCCESS) {
-                mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
-                mAvSharedMemSize = avMemSize;
-            }
-        });
     }
 }
 
 void FilterClient::closeAvSharedMemory() {
-    if (mAvSharedHandle == NULL) {
+    if (mAvSharedHandle == nullptr) {
         mAvSharedMemSize = 0;
         return;
     }
     native_handle_close(mAvSharedHandle);
     native_handle_delete(mAvSharedHandle);
     mAvSharedMemSize = 0;
-    mAvSharedHandle = NULL;
+    mAvSharedHandle = nullptr;
 }
 }  // namespace android
diff --git a/media/jni/tuner/FilterClient.h b/media/jni/tuner/FilterClient.h
index 5d78bfd..136d1f5 100644
--- a/media/jni/tuner/FilterClient.h
+++ b/media/jni/tuner/FilterClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,64 +17,30 @@
 #ifndef _ANDROID_MEDIA_TV_FILTER_CLIENT_H_
 #define _ANDROID_MEDIA_TV_FILTER_CLIENT_H_
 
-#include <aidl/android/media/tv/tuner/ITunerFilter.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterType.h>
 #include <aidl/android/media/tv/tuner/BnTunerFilterCallback.h>
-#include <aidl/android/media/tv/tuner/TunerFilterEvent.h>
-#include <aidl/android/media/tv/tuner/TunerFilterSettings.h>
-#include <aidlcommonsupport/NativeHandle.h>
-#include <android/hardware/tv/tuner/1.1/IFilter.h>
-#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
+#include <aidl/android/media/tv/tuner/ITunerFilter.h>
 #include <fmq/AidlMessageQueue.h>
-#include <fmq/MessageQueue.h>
 
 #include "ClientHelper.h"
 #include "FilterClientCallback.h"
 
 using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
 using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::tv::tuner::AvStreamType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterType;
 using ::aidl::android::media::tv::tuner::BnTunerFilterCallback;
 using ::aidl::android::media::tv::tuner::ITunerFilter;
-using ::aidl::android::media::tv::tuner::TunerDemuxIpAddress;
-using ::aidl::android::media::tv::tuner::TunerFilterAvSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterConfiguration;
-using ::aidl::android::media::tv::tuner::TunerFilterDownloadSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterEvent;
-using ::aidl::android::media::tv::tuner::TunerFilterPesDataSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterRecordSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterSectionSettings;
-using ::aidl::android::media::tv::tuner::TunerFilterSettings;
-
 using ::android::hardware::EventFlag;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
-using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
-using ::android::hardware::tv::tuner::V1_0::IFilter;
-using ::android::hardware::tv::tuner::V1_0::Result;
-using ::android::hardware::tv::tuner::V1_1::AvStreamType;
-using ::android::hardware::tv::tuner::V1_1::IFilterCallback;
 
 using namespace std;
 
 namespace android {
 
-using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-using MQDesc = MQDescriptorSync<uint8_t>;
 using AidlMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
 
@@ -84,47 +50,10 @@
 };
 
 class TunerFilterCallback : public BnTunerFilterCallback {
-
 public:
     TunerFilterCallback(sp<FilterClientCallback> filterClientCallback);
-    Status onFilterStatus(int status);
-    Status onFilterEvent(const vector<TunerFilterEvent>& filterEvents);
-
-private:
-    void getHidlFilterEvent(const vector<TunerFilterEvent>& filterEvents,
-            DemuxFilterEvent& event, DemuxFilterEventExt& eventExt);
-    void getHidlMediaEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlSectionEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlPesEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlTsRecordEvent(const vector<TunerFilterEvent>& filterEvents,
-            DemuxFilterEvent& event, DemuxFilterEventExt& eventExt);
-    void getHidlMmtpRecordEvent(const vector<TunerFilterEvent>& filterEvents,
-            DemuxFilterEvent& event, DemuxFilterEventExt& eventExt);
-    void getHidlDownloadEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlIpPayloadEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlTemiEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEvent& event);
-    void getHidlMonitorEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEventExt& eventExt);
-    void getHidlRestartEvent(
-            const vector<TunerFilterEvent>& filterEvents, DemuxFilterEventExt& eventExt);
-
-    sp<FilterClientCallback> mFilterClientCallback;
-};
-
-struct HidlFilterCallback : public IFilterCallback {
-
-public:
-    HidlFilterCallback(sp<FilterClientCallback> filterClientCallback);
-    virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
-            const DemuxFilterEventExt& filterEventExt);
-    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
-    virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
+    Status onFilterStatus(DemuxFilterStatus status);
+    Status onFilterEvent(const vector<DemuxFilterEvent>& filterEvents);
 
 private:
     sp<FilterClientCallback> mFilterClientCallback;
@@ -136,15 +65,12 @@
     FilterClient(DemuxFilterType type, shared_ptr<ITunerFilter> tunerFilter);
     ~FilterClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlFilter(sp<IFilter> filter);
-
     /**
      * Read size of data from filter FMQ into buffer.
      *
      * @return the actual reading size. -1 if failed to read.
      */
-    int read(int8_t* buffer, int size);
+    int64_t read(int8_t* buffer, int64_t size);
 
     /**
      * Get the a/v shared memory handle information
@@ -159,12 +85,12 @@
     /**
      * Configure the monitor event of the Filter.
      */
-    Result configureMonitorEvent(int monitorEventType);
+    Result configureMonitorEvent(int32_t monitorEventType);
 
     /**
      * Configure the context id of the IP Filter.
      */
-    Result configureIpFilterContextId(int cid);
+    Result configureIpFilterContextId(int32_t cid);
 
     /**
      * Configure the stream type of the media Filter.
@@ -189,12 +115,12 @@
     /**
      * Get the 32-bit filter Id.
      */
-    Result getId(uint32_t& id);
+    Result getId(int32_t& id);
 
     /**
      * Get the 64-bit filter Id.
      */
-    Result getId64Bit(uint64_t& id);
+    Result getId64Bit(int64_t& id);
 
     /**
      * Release the handle reported by the HAL for AV memory.
@@ -207,11 +133,6 @@
     Result setDataSource(sp<FilterClient> filterClient);
 
     /**
-     * Get the Hal filter to build up filter linkage.
-     */
-    sp<IFilter> getHalFilter() { return mFilter; }
-
-    /**
      * Get the Aidl filter to build up filter linkage.
      */
     shared_ptr<ITunerFilter> getAidlFilter() { return mTunerFilter; }
@@ -222,24 +143,8 @@
     Result close();
 
 private:
-    TunerFilterConfiguration getAidlFilterSettings(DemuxFilterSettings configure);
-
-    TunerFilterConfiguration getAidlTsSettings(DemuxTsFilterSettings configure);
-    TunerFilterConfiguration getAidlMmtpSettings(DemuxMmtpFilterSettings mmtp);
-    TunerFilterConfiguration getAidlIpSettings(DemuxIpFilterSettings ip);
-    TunerFilterConfiguration getAidlTlvSettings(DemuxTlvFilterSettings tlv);
-    TunerFilterConfiguration getAidlAlpSettings(DemuxAlpFilterSettings alp);
-
-    TunerFilterAvSettings getAidlAvSettings(DemuxFilterAvSettings hidlAv);
-    TunerFilterSectionSettings getAidlSectionSettings(DemuxFilterSectionSettings hidlSection);
-    TunerFilterPesDataSettings getAidlPesDataSettings(DemuxFilterPesDataSettings hidlPesData);
-    TunerFilterRecordSettings getAidlRecordSettings(DemuxFilterRecordSettings hidlRecord);
-    TunerFilterDownloadSettings getAidlDownloadSettings(DemuxFilterDownloadSettings hidlDownload);
-
-    void getAidlIpAddress(DemuxIpAddress ipAddr,
-            TunerDemuxIpAddress& srcIpAddress, TunerDemuxIpAddress& dstIpAddress);
     Result getFilterMq();
-    int copyData(int8_t* buffer, int size);
+    int64_t copyData(int8_t* buffer, int64_t size);
     void checkIsMediaFilter(DemuxFilterType type);
     void checkIsPassthroughFilter(DemuxFilterSettings configure);
     void handleAvShareMemory();
@@ -251,22 +156,8 @@
      */
     shared_ptr<ITunerFilter> mTunerFilter;
 
-    /**
-     * A 1.0 Filter HAL interface that is ready before migrating to the TunerFilter.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<IFilter> mFilter;
-
-    /**
-     * A 1.1 Filter HAL interface that is ready before migrating to the TunerFilter.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<::android::hardware::tv::tuner::V1_1::IFilter> mFilter_1_1;
-
-    AidlMQ* mFilterMQ = NULL;
-    EventFlag* mFilterMQEventFlag = NULL;
+    AidlMQ* mFilterMQ = nullptr;
+    EventFlag* mFilterMQEventFlag = nullptr;
 
     native_handle_t* mAvSharedHandle;
     uint64_t mAvSharedMemSize;
diff --git a/media/jni/tuner/FilterClientCallback.h b/media/jni/tuner/FilterClientCallback.h
index 94b7821..05e7ff0 100644
--- a/media/jni/tuner/FilterClientCallback.h
+++ b/media/jni/tuner/FilterClientCallback.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,20 +17,21 @@
 #ifndef _ANDROID_MEDIA_TV_FILTER_CLIENT_CALLBACK_H_
 #define _ANDROID_MEDIA_TV_FILTER_CLIENT_CALLBACK_H_
 
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
-using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
-using ::android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
+#include <aidl/android/hardware/tv/tuner/DemuxFilterEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterStatus.h>
+#include <utils/RefBase.h>
+
+using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
 
 using namespace std;
 
 namespace android {
 
 struct FilterClientCallback : public RefBase {
-    virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
-            const DemuxFilterEventExt& filterEventExt);
-    virtual void onFilterEvent(const DemuxFilterEvent& filterEvent);
+    virtual void onFilterEvent(const vector<DemuxFilterEvent>& filterEvents);
     virtual void onFilterStatus(const DemuxFilterStatus status);
 };
 }  // namespace android
 
-#endif  // _ANDROID_MEDIA_TV_FILTER_CLIENT_CALLBACK_H_
\ No newline at end of file
+#endif // _ANDROID_MEDIA_TV_FILTER_CLIENT_CALLBACK_H_
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index 5d9b12d..70309a0 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,1235 +16,168 @@
 
 #define LOG_TAG "FrontendClient"
 
+#include "FrontendClient.h"
+
+#include <aidl/android/hardware/tv/tuner/Constant.h>
 #include <android-base/logging.h>
 #include <utils/Log.h>
 
-#include "FrontendClient.h"
-
-using ::aidl::android::media::tv::tuner::TunerFrontendScanAtsc3PlpInfo;
-using ::aidl::android::media::tv::tuner::TunerFrontendUnionSettings;
-
-using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Bandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Modulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3TimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcAnnex;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbcSpectralInversion;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbsRolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
-using ::android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
-using ::android::hardware::tv::tuner::V1_0::FrontendInnerFec;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsRolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Modulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Rolloff;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtBandwidth;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtGuardInterval;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtMode;
-using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtModulation;
-using ::android::hardware::tv::tuner::V1_0::FrontendModulationStatus;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanAtsc3PlpInfo;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatusAtsc3PlpInfo;
-using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
-using ::android::hardware::tv::tuner::V1_1::Constant;
-using ::android::hardware::tv::tuner::V1_1::FrontendBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbGuardInterval;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbModulation;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTimeInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTransmissionMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbcBandwidth;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation;
-using ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval;
-using ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendModulation;
-using ::android::hardware::tv::tuner::V1_1::FrontendRollOff;
-using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
-using ::android::hardware::tv::tuner::V1_1::FrontendTransmissionMode;
-using ::android::hardware::tv::tuner::V1_1::FrontendType;
+using ::aidl::android::hardware::tv::tuner::Constant;
 
 namespace android {
-
 /////////////// FrontendClient ///////////////////////
-
-FrontendClient::FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend, int type) {
+FrontendClient::FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend, FrontendType type) {
     mTunerFrontend = tunerFrontend;
     mType = type;
 }
 
 FrontendClient::~FrontendClient() {
-    mTunerFrontend = NULL;
-    mFrontend = NULL;
-    mFrontend_1_1 = NULL;
-    mId = -1;
-    mType = -1;
+    mTunerFrontend = nullptr;
+    mType = FrontendType::UNDEFINED;
 }
 
 Result FrontendClient::setCallback(sp<FrontendClientCallback> frontendClientCallback) {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         shared_ptr<TunerFrontendCallback> aidlCallback =
                 ::ndk::SharedRefBase::make<TunerFrontendCallback>(frontendClientCallback);
-        aidlCallback->setFrontendType(mType);
         Status s = mTunerFrontend->setCallback(aidlCallback);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    sp<HidlFrontendCallback> hidlCallback = new HidlFrontendCallback(frontendClientCallback);
-    return mFrontend->setCallback(hidlCallback);
+    return Result::INVALID_STATE;
 }
 
-void FrontendClient::setHidlFrontend(sp<IFrontend> frontend) {
-    mFrontend = frontend;
-    mFrontend_1_1 = ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
-}
-
-// TODO: move after migration is done
-void FrontendClient::setId(int id) {
-    mId = id;
-}
-
-Result FrontendClient::tune(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    if (mTunerFrontend != NULL) {
-        TunerFrontendSettings tunerFeSettings = getAidlFrontendSettings(settings, settingsExt1_1);
-        Status s = mTunerFrontend->tune(tunerFeSettings);
+Result FrontendClient::tune(const FrontendSettings& settings) {
+    if (mTunerFrontend != nullptr) {
+        Status s = mTunerFrontend->tune(settings);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    Result result;
-    if (mFrontend_1_1 != NULL && validateExtendedSettings(settingsExt1_1)) {
-        result = mFrontend_1_1->tune_1_1(settings, settingsExt1_1);
-        return result;
-    }
-
-    if (mFrontend != NULL) {
-        result = mFrontend->tune(settings);
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FrontendClient::stopTune() {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->stopTune();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend != NULL) {
-        Result result = mFrontend->stopTune();
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
-Result FrontendClient::scan(const FrontendSettings& settings, FrontendScanType type,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    if (mTunerFrontend != NULL) {
-        TunerFrontendSettings tunerFeSettings = getAidlFrontendSettings(settings, settingsExt1_1);
-        Status s = mTunerFrontend->scan(tunerFeSettings, (int)type);
+Result FrontendClient::scan(const FrontendSettings& settings, FrontendScanType type) {
+    if (mTunerFrontend != nullptr) {
+        Status s = mTunerFrontend->scan(settings, type);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    Result result;
-    if (mFrontend_1_1 != NULL && validateExtendedSettings(settingsExt1_1)) {
-        result = mFrontend_1_1->scan_1_1(settings, type, settingsExt1_1);
-        return result;
-    }
-
-    if (mFrontend != NULL) {
-        result = mFrontend->scan(settings, type);
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FrontendClient::stopScan() {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->stopScan();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend != NULL) {
-        Result result = mFrontend->stopScan();
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
 vector<FrontendStatus> FrontendClient::getStatus(vector<FrontendStatusType> statusTypes) {
     vector<FrontendStatus> status;
 
-    if (mTunerFrontend != NULL) {
-        vector<TunerFrontendStatus> aidlStatus;
-        vector<int> types;
-        for (auto t : statusTypes) {
-            types.push_back((int)t);
-        }
-        Status s = mTunerFrontend->getStatus(types, &aidlStatus);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return status;
-        }
-        return getHidlStatus(aidlStatus);
-    }
-
-    if (mFrontend != NULL && statusTypes.size() > 0) {
-        Result res;
-        mFrontend->getStatus(statusTypes,
-                [&](Result r, const hidl_vec<FrontendStatus>& s) {
-                    res = r;
-                    status = s;
-                });
-        if (res != Result::SUCCESS) {
-            status.clear();
-            return status;
-        }
-    }
-
-    return status;
-}
-
-vector<FrontendStatusExt1_1> FrontendClient::getStatusExtended_1_1(
-        vector<FrontendStatusTypeExt1_1> statusTypes) {
-    vector<FrontendStatusExt1_1> status;
-
-    if (mTunerFrontend != NULL) {
-        vector<TunerFrontendStatus> aidlStatus;
-        vector<int> types;
-        for (auto t : statusTypes) {
-            types.push_back((int)t);
-        }
-        Status s = mTunerFrontend->getStatusExtended_1_1(types, &aidlStatus);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return status;
-        }
-        return getHidlStatusExt(aidlStatus);
-    }
-
-    if (mFrontend_1_1 != NULL && statusTypes.size() > 0) {
-        Result res;
-        mFrontend_1_1->getStatusExt1_1(statusTypes,
-            [&](Result r, const hidl_vec<FrontendStatusExt1_1>& s) {
-                res = r;
-                status = s;
-            });
-        if (res != Result::SUCCESS) {
-            status.clear();
-            return status;
-        }
+    if (mTunerFrontend != nullptr) {
+        mTunerFrontend->getStatus(statusTypes, &status);
     }
 
     return status;
 }
 
 Result FrontendClient::setLnb(sp<LnbClient> lnbClient) {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->setLnb(lnbClient->getAidlLnb());
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend != NULL) {
-        Result result = mFrontend->setLnb(lnbClient->getId());
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FrontendClient::setLna(bool bEnable) {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->setLna(bEnable);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend != NULL) {
-        Result result = mFrontend->setLna(bEnable);
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
-int FrontendClient::linkCiCamToFrontend(int ciCamId) {
-    int ltsId = (int)Constant::INVALID_LTS_ID;
+int32_t FrontendClient::linkCiCamToFrontend(int32_t ciCamId) {
+    int32_t ltsId = static_cast<int32_t>(Constant::INVALID_LTS_ID);
 
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->linkCiCamToFrontend(ciCamId, &ltsId);
-        if (ClientHelper::getServiceSpecificErrorCode(s) == Result::SUCCESS) {
-            return ltsId;
-        }
-        return (int)Constant::INVALID_LTS_ID;
-    }
-
-    if (mFrontend_1_1 != NULL) {
-        Result res;
-        mFrontend_1_1->linkCiCam(static_cast<uint32_t>(ciCamId),
-            [&](Result r, uint32_t id) {
-                res = r;
-                ltsId = id;
-            });
-        if (res != Result::SUCCESS) {
-            return (int)Constant::INVALID_LTS_ID;
+        if (!s.isOk()) {
+            return static_cast<int32_t>(Constant::INVALID_LTS_ID);
         }
     }
 
     return ltsId;
 }
 
-Result FrontendClient::unlinkCiCamToFrontend(int ciCamId) {
-    if (mTunerFrontend != NULL) {
+Result FrontendClient::unlinkCiCamToFrontend(int32_t ciCamId) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->unlinkCiCamToFrontend(ciCamId);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend_1_1 != NULL) {
-        return mFrontend_1_1->unlinkCiCam(static_cast<uint32_t>(ciCamId));
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result FrontendClient::close() {
-    if (mTunerFrontend != NULL) {
+    if (mTunerFrontend != nullptr) {
         Status s = mTunerFrontend->close();
-        mTunerFrontend = NULL;
+        mTunerFrontend = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mFrontend != NULL) {
-        Result result = mFrontend->close();
-        mFrontend = NULL;
-        mFrontend_1_1 = NULL;
-        return result;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// TunerFrontend Helper Methods ///////////////////////
-
 shared_ptr<ITunerFrontend> FrontendClient::getAidlFrontend() {
     return mTunerFrontend;
 }
 
-int FrontendClient::getId() {
-    if (mTunerFrontend != NULL) {
-        Status s = mTunerFrontend->getFrontendId(&mId);
-        if (ClientHelper::getServiceSpecificErrorCode(s) == Result::SUCCESS) {
-            return mId;
-        }
-        ALOGE("Failed to getFrontendId from Tuner Frontend");
-        return -1;
-    }
-
-    if (mFrontend != NULL) {
-        return mId;
-    }
-
-    return -1;
-}
-
-vector<FrontendStatus> FrontendClient::getHidlStatus(vector<TunerFrontendStatus>& aidlStatus) {
-    vector<FrontendStatus> hidlStatus;
-    for (TunerFrontendStatus s : aidlStatus) {
-        FrontendStatus status = FrontendStatus();
-        switch (s.getTag()) {
-            case TunerFrontendStatus::isDemodLocked: {
-                status.isDemodLocked(s.get<TunerFrontendStatus::isDemodLocked>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::snr: {
-                status.snr(s.get<TunerFrontendStatus::snr>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::ber: {
-                status.ber((uint32_t)s.get<TunerFrontendStatus::ber>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::per: {
-                status.per((uint32_t)s.get<TunerFrontendStatus::per>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::preBer: {
-                status.preBer((uint32_t)s.get<TunerFrontendStatus::preBer>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::signalQuality: {
-                status.signalQuality((uint32_t)s.get<TunerFrontendStatus::signalQuality>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::signalStrength: {
-                status.signalStrength(s.get<TunerFrontendStatus::signalStrength>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::symbolRate: {
-                status.symbolRate((uint32_t)s.get<TunerFrontendStatus::symbolRate>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::innerFec: {
-                status.innerFec(static_cast<FrontendInnerFec>(
-                        s.get<TunerFrontendStatus::innerFec>()));
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::modulation: {
-                auto aidlMod = s.get<TunerFrontendStatus::modulation>();
-                FrontendModulationStatus modulation;
-                switch (mType) {
-                    case (int)FrontendType::DVBC:
-                        modulation.dvbc(static_cast<FrontendDvbcModulation>(aidlMod));
-                        status.modulation(modulation);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DVBS:
-                        modulation.dvbs(static_cast<FrontendDvbsModulation>(aidlMod));
-                        status.modulation(modulation);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBS:
-                        modulation.isdbs(static_cast<FrontendIsdbsModulation>(aidlMod));
-                        status.modulation(modulation);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBS3:
-                        modulation.isdbs3(static_cast<FrontendIsdbs3Modulation>(aidlMod));
-                        status.modulation(modulation);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBT:
-                        modulation.isdbt(static_cast<FrontendIsdbtModulation>(aidlMod));
-                        status.modulation(modulation);
-                        hidlStatus.push_back(status);
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            }
-            case TunerFrontendStatus::inversion: {
-                status.inversion(static_cast<FrontendDvbcSpectralInversion>(
-                        s.get<TunerFrontendStatus::inversion>()));
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::lnbVoltage: {
-                status.lnbVoltage(static_cast<LnbVoltage>(
-                        s.get<TunerFrontendStatus::lnbVoltage>()));
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::plpId: {
-                status.plpId((uint8_t)s.get<TunerFrontendStatus::plpId>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isEWBS: {
-                status.isEWBS(s.get<TunerFrontendStatus::isEWBS>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::agc: {
-                status.agc((uint8_t)s.get<TunerFrontendStatus::agc>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isLnaOn: {
-                status.isLnaOn(s.get<TunerFrontendStatus::isLnaOn>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isLayerError: {
-                auto aidlE = s.get<TunerFrontendStatus::isLayerError>();
-                hidl_vec<bool> e(aidlE.begin(), aidlE.end());
-                status.isLayerError(e);
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::mer: {
-                status.mer(s.get<TunerFrontendStatus::mer>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::freqOffset: {
-                status.freqOffset(s.get<TunerFrontendStatus::freqOffset>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::hierarchy: {
-                status.hierarchy(static_cast<FrontendDvbtHierarchy>(
-                        s.get<TunerFrontendStatus::hierarchy>()));
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isRfLocked: {
-                status.isRfLocked(s.get<TunerFrontendStatus::isRfLocked>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::plpInfo: {
-                int size = s.get<TunerFrontendStatus::plpInfo>().size();
-                hidl_vec<FrontendStatusAtsc3PlpInfo> info(size);
-                for (int i = 0; i < size; i++) {
-                    auto aidlInfo = s.get<TunerFrontendStatus::plpInfo>()[i];
-                    info[i] = {
-                        .plpId = (uint8_t)aidlInfo.plpId,
-                        .isLocked = aidlInfo.isLocked,
-                        .uec = (uint32_t)aidlInfo.uec,
-                    };
-                }
-                status.plpInfo(info);
-                hidlStatus.push_back(status);
-                break;
-            }
-            default:
-                break;
+int32_t FrontendClient::getId() {
+    if (mTunerFrontend != nullptr) {
+        int32_t id;
+        Status s = mTunerFrontend->getFrontendId(&id);
+        if (s.isOk()) {
+            return id;
         }
     }
-    return hidlStatus;
-}
 
-vector<FrontendStatusExt1_1> FrontendClient::getHidlStatusExt(
-        vector<TunerFrontendStatus>& aidlStatus) {
-    vector<FrontendStatusExt1_1> hidlStatus;
-    for (TunerFrontendStatus s : aidlStatus) {
-        FrontendStatusExt1_1 status;
-        switch (s.getTag()) {
-            case TunerFrontendStatus::modulations: {
-                vector<FrontendModulation> ms;
-                for (auto aidlMod : s.get<TunerFrontendStatus::modulations>()) {
-                    FrontendModulation m;
-                    switch (mType) {
-                        case (int)FrontendType::DVBC:
-                            m.dvbc(static_cast<FrontendDvbcModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::DVBS:
-                            m.dvbs(static_cast<FrontendDvbsModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::DVBT:
-                            m.dvbt(static_cast<FrontendDvbtConstellation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::ISDBS:
-                            m.isdbs(static_cast<FrontendIsdbsModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::ISDBS3:
-                            m.isdbs3(static_cast<FrontendIsdbs3Modulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::ISDBT:
-                            m.isdbt(static_cast<FrontendIsdbtModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::ATSC:
-                            m.atsc(static_cast<FrontendAtscModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::ATSC3:
-                            m.atsc3(static_cast<FrontendAtsc3Modulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        case (int)FrontendType::DTMB:
-                            m.dtmb(static_cast<FrontendDtmbModulation>(aidlMod));
-                            ms.push_back(m);
-                            break;
-                        default:
-                            break;
-                    }
-                }
-                if (ms.size() > 0) {
-                    status.modulations(ms);
-                    hidlStatus.push_back(status);
-                }
-                break;
-            }
-            case TunerFrontendStatus::bers: {
-                auto aidlB = s.get<TunerFrontendStatus::bers>();
-                hidl_vec<uint32_t> b(aidlB.begin(), aidlB.end());
-                status.bers(b);
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::codeRates: {
-                vector<hardware::tv::tuner::V1_1::FrontendInnerFec> codeRates;
-                for (auto aidlCodeRate : s.get<TunerFrontendStatus::codeRates>()) {
-                    codeRates.push_back(
-                            static_cast<hardware::tv::tuner::V1_1::FrontendInnerFec>(aidlCodeRate));
-                }
-                if (codeRates.size() > 0) {
-                    status.codeRates(codeRates);
-                    hidlStatus.push_back(status);
-                }
-                break;
-            }
-            case TunerFrontendStatus::bandwidth: {
-                auto aidlBand = s.get<TunerFrontendStatus::bandwidth>();
-                FrontendBandwidth band;
-                switch (mType) {
-                    case (int)FrontendType::ATSC3:
-                        band.atsc3(static_cast<FrontendAtsc3Bandwidth>(aidlBand));
-                        status.bandwidth(band);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DVBC:
-                        band.dvbc(static_cast<FrontendDvbcBandwidth>(aidlBand));
-                        status.bandwidth(band);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DVBT:
-                        band.dvbt(static_cast<FrontendDvbtBandwidth>(aidlBand));
-                        status.bandwidth(band);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBT:
-                        band.isdbt(static_cast<FrontendIsdbtBandwidth>(aidlBand));
-                        status.bandwidth(band);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DTMB:
-                        band.dtmb(static_cast<FrontendDtmbBandwidth>(aidlBand));
-                        status.bandwidth(band);
-                        hidlStatus.push_back(status);
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            }
-            case TunerFrontendStatus::interval: {
-                auto aidlInter = s.get<TunerFrontendStatus::interval>();
-                FrontendGuardInterval inter;
-                switch (mType) {
-                    case (int)FrontendType::DVBT:
-                        inter.dvbt(static_cast<FrontendDvbtGuardInterval>(aidlInter));
-                        status.interval(inter);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBT:
-                        inter.isdbt(static_cast<FrontendIsdbtGuardInterval>(aidlInter));
-                        status.interval(inter);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DTMB:
-                        inter.dtmb(static_cast<FrontendDtmbGuardInterval>(aidlInter));
-                        status.interval(inter);
-                        hidlStatus.push_back(status);
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            }
-            case TunerFrontendStatus::transmissionMode: {
-                auto aidlTran = s.get<TunerFrontendStatus::transmissionMode>();
-                FrontendTransmissionMode trans;
-                switch (mType) {
-                    case (int)FrontendType::DVBT:
-                        trans.dvbt(static_cast<FrontendDvbtTransmissionMode>(aidlTran));
-                        status.transmissionMode(trans);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBT:
-                        trans.isdbt(static_cast<FrontendIsdbtMode>(aidlTran));
-                        status.transmissionMode(trans);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::DTMB:
-                        trans.dtmb(static_cast<FrontendDtmbTransmissionMode>(aidlTran));
-                        status.transmissionMode(trans);
-                        hidlStatus.push_back(status);
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            }
-            case TunerFrontendStatus::uec: {
-                status.uec((uint32_t)s.get<TunerFrontendStatus::uec>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::systemId: {
-                status.systemId((uint16_t)s.get<TunerFrontendStatus::systemId>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::interleaving: {
-                vector<FrontendInterleaveMode> modes;
-                for (auto aidlInter : s.get<TunerFrontendStatus::interleaving>()) {
-                    FrontendInterleaveMode mode;
-                    switch (mType) {
-                        case (int)FrontendType::DVBC:
-                            mode.dvbc(static_cast<FrontendCableTimeInterleaveMode>(aidlInter));
-                            modes.push_back(mode);
-                            break;
-                        case (int)FrontendType::ATSC3:
-                            mode.atsc3(static_cast<FrontendAtsc3TimeInterleaveMode>(aidlInter));
-                            modes.push_back(mode);
-                            break;
-                        case (int)FrontendType::DTMB:
-                            mode.dtmb(static_cast<FrontendDtmbTimeInterleaveMode>(aidlInter));
-                            modes.push_back(mode);
-                            break;
-                        default:
-                            break;
-                    }
-                }
-                if (modes.size() > 0) {
-                    status.interleaving(modes);
-                    hidlStatus.push_back(status);
-                }
-                break;
-            }
-            case TunerFrontendStatus::isdbtSegment: {
-                auto aidlSeg = s.get<TunerFrontendStatus::isdbtSegment>();
-                hidl_vec<uint8_t> s(aidlSeg.begin(), aidlSeg.end());
-                status.isdbtSegment(s);
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::tsDataRate: {
-                auto aidlTs = s.get<TunerFrontendStatus::tsDataRate>();
-                hidl_vec<uint32_t> ts(aidlTs.begin(), aidlTs.end());
-                status.tsDataRate(ts);
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::rollOff: {
-                auto aidlRoll = s.get<TunerFrontendStatus::rollOff>();
-                FrontendRollOff roll;
-                switch (mType) {
-                    case (int)FrontendType::DVBS:
-                        roll.dvbs(static_cast<FrontendDvbsRolloff>(aidlRoll));
-                        status.rollOff(roll);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBS:
-                        roll.isdbs(static_cast<FrontendIsdbsRolloff>(aidlRoll));
-                        status.rollOff(roll);
-                        hidlStatus.push_back(status);
-                        break;
-                    case (int)FrontendType::ISDBS3:
-                        roll.isdbs3(static_cast<FrontendIsdbs3Rolloff>(aidlRoll));
-                        status.rollOff(roll);
-                        hidlStatus.push_back(status);
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            }
-            case TunerFrontendStatus::isMiso: {
-                status.isMiso(s.get<TunerFrontendStatus::isMiso>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isLinear: {
-                status.isLinear(s.get<TunerFrontendStatus::isLinear>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            case TunerFrontendStatus::isShortFrames: {
-                status.isShortFrames(s.get<TunerFrontendStatus::isShortFrames>());
-                hidlStatus.push_back(status);
-                break;
-            }
-            default:
-                break;
-        }
-    }
-    return hidlStatus;
-}
-
-TunerFrontendSettings FrontendClient::getAidlFrontendSettings(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    bool isExtended = validateExtendedSettings(settingsExt1_1);
-    TunerFrontendSettings s{
-        .isExtended = isExtended,
-        .endFrequency = (int) settingsExt1_1.endFrequency,
-        .inversion = (int) settingsExt1_1.inversion,
-    };
-
-    if (settingsExt1_1.settingExt.getDiscriminator()
-            == FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::dtmb) {
-        s.settings.set<TunerFrontendUnionSettings::dtmb>(getAidlDtmbSettings(settingsExt1_1));
-        return s;
-    }
-
-    switch (settings.getDiscriminator()) {
-        case FrontendSettings::hidl_discriminator::analog: {
-            s.settings.set<TunerFrontendUnionSettings::analog>(
-                    getAidlAnalogSettings(settings, settingsExt1_1));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::atsc: {
-            s.settings.set<TunerFrontendUnionSettings::atsc>(getAidlAtscSettings(settings));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::atsc3: {
-            s.settings.set<TunerFrontendUnionSettings::atsc3>(getAidlAtsc3Settings(settings));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::dvbs: {
-            s.settings.set<TunerFrontendUnionSettings::dvbs>(
-                    getAidlDvbsSettings(settings, settingsExt1_1));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::dvbc: {
-            s.settings.set<TunerFrontendUnionSettings::cable>(
-                    getAidlCableSettings(settings, settingsExt1_1));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::dvbt: {
-            s.settings.set<TunerFrontendUnionSettings::dvbt>(
-                    getAidlDvbtSettings(settings, settingsExt1_1));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::isdbs: {
-            s.settings.set<TunerFrontendUnionSettings::isdbs>(getAidlIsdbsSettings(settings));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::isdbs3: {
-            s.settings.set<TunerFrontendUnionSettings::isdbs3>(getAidlIsdbs3Settings(settings));
-            break;
-        }
-        case FrontendSettings::hidl_discriminator::isdbt: {
-            s.settings.set<TunerFrontendUnionSettings::isdbt>(getAidlIsdbtSettings(settings));
-            break;
-        }
-        default:
-            break;
-    }
-    return s;
-}
-
-TunerFrontendAnalogSettings FrontendClient::getAidlAnalogSettings(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    TunerFrontendAnalogSettings analogSettings{
-        .frequency = (int)settings.analog().frequency,
-        .signalType = (int)settings.analog().type,
-        .sifStandard = (int)settings.analog().sifStandard,
-    };
-    if (settingsExt1_1.settingExt.getDiscriminator()
-            == FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::analog) {
-        analogSettings.isExtended = true;
-        analogSettings.aftFlag = (int)settingsExt1_1.settingExt.analog().aftFlag;
-    } else {
-        analogSettings.isExtended = false;
-    }
-    return analogSettings;
-}
-
-TunerFrontendDvbsSettings FrontendClient::getAidlDvbsSettings(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    TunerFrontendDvbsSettings dvbsSettings{
-        .frequency = (int)settings.dvbs().frequency,
-        .modulation = (int)settings.dvbs().modulation,
-        .codeRate = {
-            .fec = (long)settings.dvbs().coderate.fec,
-            .isLinear = settings.dvbs().coderate.isLinear,
-            .isShortFrames = settings.dvbs().coderate.isShortFrames,
-            .bitsPer1000Symbol = (int)settings.dvbs().coderate.bitsPer1000Symbol,
-        },
-        .symbolRate = (int)settings.dvbs().symbolRate,
-        .rolloff = (int)settings.dvbs().rolloff,
-        .pilot = (int)settings.dvbs().pilot,
-        .inputStreamId = (int)settings.dvbs().inputStreamId,
-        .standard = (int)settings.dvbs().standard,
-        .vcm = (int)settings.dvbs().vcmMode,
-    };
-    if (settingsExt1_1.settingExt.getDiscriminator()
-            == FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::dvbs) {
-        dvbsSettings.isExtended = true;
-        dvbsSettings.scanType = (int)settingsExt1_1.settingExt.dvbs().scanType;
-        dvbsSettings.isDiseqcRxMessage = settingsExt1_1.settingExt.dvbs().isDiseqcRxMessage;
-    } else {
-        dvbsSettings.isExtended = false;
-    }
-    return dvbsSettings;
-}
-
-TunerFrontendCableSettings FrontendClient::getAidlCableSettings(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    TunerFrontendCableSettings cableSettings{
-        .frequency = (int)settings.dvbc().frequency,
-        .modulation = (int)settings.dvbc().modulation,
-        .innerFec = (long)settings.dvbc().fec,
-        .symbolRate = (int)settings.dvbc().symbolRate,
-        .outerFec = (int)settings.dvbc().outerFec,
-        .annex = (int)settings.dvbc().annex,
-        .spectralInversion = (int)settings.dvbc().spectralInversion,
-    };
-    if (settingsExt1_1.settingExt.getDiscriminator()
-            == FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::dvbc) {
-        cableSettings.isExtended = true;
-        cableSettings.interleaveMode = (int)settingsExt1_1.settingExt.dvbc().interleaveMode;
-        cableSettings.bandwidth = (int)settingsExt1_1.settingExt.dvbc().bandwidth;
-    } else {
-        cableSettings.isExtended = false;
-    }
-    return cableSettings;
-}
-
-TunerFrontendDvbtSettings FrontendClient::getAidlDvbtSettings(const FrontendSettings& settings,
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    TunerFrontendDvbtSettings dvbtSettings{
-        .frequency = (int)settings.dvbt().frequency,
-        .transmissionMode = (int)settings.dvbt().transmissionMode,
-        .bandwidth = (int)settings.dvbt().bandwidth,
-        .constellation = (int)settings.dvbt().constellation,
-        .hierarchy = (int)settings.dvbt().hierarchy,
-        .hpCodeRate = (int)settings.dvbt().hpCoderate,
-        .lpCodeRate = (int)settings.dvbt().lpCoderate,
-        .guardInterval = (int)settings.dvbt().guardInterval,
-        .isHighPriority = settings.dvbt().isHighPriority,
-        .standard = (int)settings.dvbt().standard,
-        .isMiso = settings.dvbt().isMiso,
-        .plpMode = (int)settings.dvbt().plpMode,
-        .plpId = (int)settings.dvbt().plpId,
-        .plpGroupId = (int)settings.dvbt().plpGroupId,
-    };
-    if (settingsExt1_1.settingExt.getDiscriminator()
-            == FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::dvbt) {
-        dvbtSettings.isExtended = true;
-        dvbtSettings.constellation = (int)settingsExt1_1.settingExt.dvbt().constellation;
-        dvbtSettings.transmissionMode =
-                (int)settingsExt1_1.settingExt.dvbt().transmissionMode;
-    } else {
-        dvbtSettings.isExtended = false;
-    }
-    return dvbtSettings;
-}
-
-TunerFrontendDtmbSettings FrontendClient::getAidlDtmbSettings(
-        const FrontendSettingsExt1_1& settingsExt1_1) {
-    TunerFrontendDtmbSettings dtmbSettings{
-        .frequency = (int)settingsExt1_1.settingExt.dtmb().frequency,
-        .transmissionMode = (int)settingsExt1_1.settingExt.dtmb().transmissionMode,
-        .bandwidth = (int)settingsExt1_1.settingExt.dtmb().bandwidth,
-        .modulation = (int)settingsExt1_1.settingExt.dtmb().modulation,
-        .codeRate = (int)settingsExt1_1.settingExt.dtmb().codeRate,
-        .guardInterval = (int)settingsExt1_1.settingExt.dtmb().guardInterval,
-        .interleaveMode = (int)settingsExt1_1.settingExt.dtmb().interleaveMode,
-    };
-    return dtmbSettings;
-}
-
-TunerFrontendAtscSettings FrontendClient::getAidlAtscSettings(const FrontendSettings& settings) {
-    TunerFrontendAtscSettings atscSettings{
-        .frequency = (int)settings.atsc().frequency,
-        .modulation = (int)settings.atsc().modulation,
-    };
-    return atscSettings;
-}
-
-TunerFrontendAtsc3Settings FrontendClient::getAidlAtsc3Settings(const FrontendSettings& settings) {
-    TunerFrontendAtsc3Settings atsc3Settings{
-        .frequency = (int)settings.atsc3().frequency,
-        .bandwidth = (int)settings.atsc3().bandwidth,
-        .demodOutputFormat = (int)settings.atsc3().demodOutputFormat,
-    };
-    atsc3Settings.plpSettings.resize(settings.atsc3().plpSettings.size());
-    for (auto plpSetting : settings.atsc3().plpSettings) {
-        atsc3Settings.plpSettings.push_back({
-            .plpId = (int)plpSetting.plpId,
-            .modulation = (int)plpSetting.modulation,
-            .interleaveMode = (int)plpSetting.interleaveMode,
-            .codeRate = (int)plpSetting.codeRate,
-            .fec = (int)plpSetting.fec,
-        });
-    }
-    return atsc3Settings;
-}
-
-TunerFrontendIsdbsSettings FrontendClient::getAidlIsdbsSettings(const FrontendSettings& settings) {
-    TunerFrontendIsdbsSettings isdbsSettings{
-        .frequency = (int)settings.isdbs().frequency,
-        .streamId = (char16_t)settings.isdbs().streamId,
-        .streamIdType = (int)settings.isdbs().streamIdType,
-        .modulation = (int)settings.isdbs().modulation,
-        .codeRate = (int)settings.isdbs().coderate,
-        .symbolRate = (int)settings.isdbs().symbolRate,
-        .rolloff = (int)settings.isdbs().rolloff,
-    };
-    return isdbsSettings;
-}
-
-TunerFrontendIsdbs3Settings FrontendClient::getAidlIsdbs3Settings(
-        const FrontendSettings& settings) {
-    TunerFrontendIsdbs3Settings isdbs3Settings{
-        .frequency = (int)settings.isdbs3().frequency,
-        .streamId = (char16_t)settings.isdbs3().streamId,
-        .streamIdType = (int)settings.isdbs3().streamIdType,
-        .modulation = (int)settings.isdbs3().modulation,
-        .codeRate = (int)settings.isdbs3().coderate,
-        .symbolRate = (int)settings.isdbs3().symbolRate,
-        .rolloff = (int)settings.isdbs3().rolloff,
-    };
-    return isdbs3Settings;
-}
-
-TunerFrontendIsdbtSettings FrontendClient::getAidlIsdbtSettings(const FrontendSettings& settings) {
-    TunerFrontendIsdbtSettings isdbtSettings{
-        .frequency = (int)settings.isdbt().frequency,
-        .modulation = (int)settings.isdbt().modulation,
-        .bandwidth = (int)settings.isdbt().bandwidth,
-        .mode = (int)settings.isdbt().mode,
-        .codeRate = (int)settings.isdbt().coderate,
-        .guardInterval = (int)settings.isdbt().guardInterval,
-        .serviceAreaId = (int)settings.isdbt().serviceAreaId,
-    };
-    return isdbtSettings;
-}
-
-bool FrontendClient::validateExtendedSettings(const FrontendSettingsExt1_1& settingsExt1_1) {
-    return settingsExt1_1.endFrequency != (uint32_t)Constant::INVALID_FRONTEND_SETTING_FREQUENCY
-            || settingsExt1_1.inversion != FrontendSpectralInversion::UNDEFINED
-            || settingsExt1_1.settingExt.getDiscriminator()
-                    != FrontendSettingsExt1_1::SettingsExt::hidl_discriminator::noinit;
-}
-
-/////////////// TunerFrontendCallback ///////////////////////
-
-TunerFrontendCallback::TunerFrontendCallback(sp<FrontendClientCallback> frontendClientCallback)
-        : mFrontendClientCallback(frontendClientCallback) {}
-
-Status TunerFrontendCallback::onEvent(int frontendEventType) {
-    if (mFrontendClientCallback != NULL) {
-        mFrontendClientCallback->onEvent(static_cast<FrontendEventType>(frontendEventType));
-        return Status::ok();
-    }
-    return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
-}
-
-Status TunerFrontendCallback::onScanMessage(int messageType,
-        const TunerFrontendScanMessage& message) {
-    if (mFrontendClientCallback != NULL) {
-        if (!is1_1ExtendedScanMessage(messageType)) {
-            mFrontendClientCallback->onScanMessage(
-                    static_cast<FrontendScanMessageType>(messageType),
-                    getHalScanMessage(messageType, message));
-        } else {
-            mFrontendClientCallback->onScanMessageExt1_1(
-                    static_cast<FrontendScanMessageTypeExt1_1>(messageType),
-                    getHalScanMessageExt1_1(messageType, message));
-        }
-        return Status::ok();
-    }
-    return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
+    return static_cast<int32_t>(Constant::INVALID_FRONTEND_ID);
 }
 
 /////////////// IFrontendCallback ///////////////////////
-
-HidlFrontendCallback::HidlFrontendCallback(sp<FrontendClientCallback> frontendClientCallback)
+TunerFrontendCallback::TunerFrontendCallback(sp<FrontendClientCallback> frontendClientCallback)
         : mFrontendClientCallback(frontendClientCallback) {}
 
-Return<void> HidlFrontendCallback::onEvent(FrontendEventType frontendEventType) {
-    if (mFrontendClientCallback != NULL) {
+Status TunerFrontendCallback::onEvent(FrontendEventType frontendEventType) {
+    if (mFrontendClientCallback != nullptr) {
         mFrontendClientCallback->onEvent(frontendEventType);
+        return Status::ok();
     }
-    return Void();
+    return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
-Return<void> HidlFrontendCallback::onScanMessage(FrontendScanMessageType type,
-        const FrontendScanMessage& message) {
-    if (mFrontendClientCallback != NULL) {
-        mFrontendClientCallback->onScanMessage(type, message);
+Status TunerFrontendCallback::onScanMessage(FrontendScanMessageType messageType,
+                                            const FrontendScanMessage& message) {
+    if (mFrontendClientCallback != nullptr) {
+        mFrontendClientCallback->onScanMessage(messageType, message);
+        return Status::ok();
     }
-    return Void();
+    return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
-Return<void> HidlFrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
-        const FrontendScanMessageExt1_1& message) {
-    if (mFrontendClientCallback != NULL) {
-        mFrontendClientCallback->onScanMessageExt1_1(type, message);
-    }
-    return Void();
-}
-
-/////////////// FrontendClientCallback Helper Methods ///////////////////////
-
-FrontendScanMessage TunerFrontendCallback::getHalScanMessage(
-        int messageType, const TunerFrontendScanMessage& message) {
-    FrontendScanMessage scanMessage;
-    switch (messageType) {
-        case (int) FrontendScanMessageType::LOCKED:
-            scanMessage.isLocked(message.get<TunerFrontendScanMessage::isLocked>());
-            break;
-        case (int) FrontendScanMessageType::END:
-            scanMessage.isEnd(message.get<TunerFrontendScanMessage::isEnd>());
-            break;
-        case (int) FrontendScanMessageType::PROGRESS_PERCENT:
-            scanMessage.progressPercent(message.get<TunerFrontendScanMessage::progressPercent>());
-            break;
-        case (int) FrontendScanMessageType::FREQUENCY: {
-            vector<int> f = message.get<TunerFrontendScanMessage::frequencies>();
-            hidl_vec<uint32_t> frequencies(begin(f), end(f));
-            scanMessage.frequencies(frequencies);
-            break;
-        }
-        case (int) FrontendScanMessageType::SYMBOL_RATE: {
-            vector<int> s = message.get<TunerFrontendScanMessage::symbolRates>();
-            hidl_vec<uint32_t> symbolRates(begin(s), end(s));
-            scanMessage.symbolRates(symbolRates);
-            break;
-        }
-        case (int) FrontendScanMessageType::HIERARCHY:
-            scanMessage.hierarchy(static_cast<FrontendDvbtHierarchy>(
-                    message.get<TunerFrontendScanMessage::hierarchy>()));
-            break;
-        case (int) FrontendScanMessageType::ANALOG_TYPE:
-            scanMessage.analogType(static_cast<FrontendAnalogType>(
-                    message.get<TunerFrontendScanMessage::analogType>()));
-            break;
-        case (int) FrontendScanMessageType::PLP_IDS: {
-            vector<uint8_t> p = message.get<TunerFrontendScanMessage::plpIds>();
-            hidl_vec<uint8_t> plpIds(begin(p), end(p));
-            scanMessage.plpIds(plpIds);
-            break;
-        }
-        case (int) FrontendScanMessageType::GROUP_IDS: {
-            vector<uint8_t> g = message.get<TunerFrontendScanMessage::groupIds>();
-            hidl_vec<uint8_t> groupIds(begin(g), end(g));
-            scanMessage.groupIds(groupIds);
-            break;
-        }
-        case (int) FrontendScanMessageType::INPUT_STREAM_IDS: {
-            vector<char16_t> i = message.get<TunerFrontendScanMessage::inputStreamIds>();
-            hidl_vec<uint16_t> inputStreamIds(begin(i), end(i));
-            scanMessage.inputStreamIds(inputStreamIds);
-            break;
-        }
-        case (int) FrontendScanMessageType::STANDARD: {
-            FrontendScanMessage::Standard std;
-            int standard = message.get<TunerFrontendScanMessage::std>();
-            switch (mType) {
-                case (int) FrontendType::DVBS:
-                    std.sStd(static_cast<FrontendDvbsStandard>(standard));
-                    scanMessage.std(std);
-                    break;
-                case (int) FrontendType::DVBT:
-                    std.tStd(static_cast<FrontendDvbtStandard>(standard));
-                    scanMessage.std(std);
-                    break;
-                case (int) FrontendType::ANALOG:
-                    std.sifStd(static_cast<FrontendAnalogSifStandard>(standard));
-                    scanMessage.std(std);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        }
-        case (int) FrontendScanMessageType::ATSC3_PLP_INFO: {
-            vector<TunerFrontendScanAtsc3PlpInfo> plp =
-                    message.get<TunerFrontendScanMessage::atsc3PlpInfos>();
-            hidl_vec<FrontendScanAtsc3PlpInfo> plpInfo;
-            int size = plp.size();
-            plpInfo.resize(size);
-            for (int i = 0; i < size; i++) {
-                auto info = message.get<TunerFrontendScanMessage::atsc3PlpInfos>()[i];
-                FrontendScanAtsc3PlpInfo p{
-                    .plpId = static_cast<uint8_t>(info.plpId),
-                    .bLlsFlag = info.llsFlag,
-                };
-                plpInfo[i] = p;
-            }
-            scanMessage.atsc3PlpInfos(plpInfo);
-            break;
-        }
-        default:
-            break;
-    }
-    return scanMessage;
-}
-
-FrontendScanMessageExt1_1 TunerFrontendCallback::getHalScanMessageExt1_1(
-        int messageType, const TunerFrontendScanMessage& message) {
-    FrontendScanMessageExt1_1 scanMessage;
-    switch (messageType) {
-        case (int) FrontendScanMessageTypeExt1_1::HIGH_PRIORITY:
-            scanMessage.isHighPriority(message.get<TunerFrontendScanMessage::isHighPriority>());
-            break;
-        case (int) FrontendScanMessageTypeExt1_1::DVBC_ANNEX:
-            scanMessage.annex(static_cast<FrontendDvbcAnnex>(
-                    message.get<TunerFrontendScanMessage::annex>()));
-            break;
-        case (int) FrontendScanMessageTypeExt1_1::MODULATION: {
-            FrontendModulation m;
-            int modulation = message.get<TunerFrontendScanMessage::modulation>();
-            switch (mType) {
-                case (int) FrontendType::DVBC:
-                    m.dvbc(static_cast<FrontendDvbcModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::DVBS:
-                    m.dvbs(static_cast<FrontendDvbsModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::DVBT:
-                    m.dvbt(static_cast<FrontendDvbtConstellation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::ISDBS:
-                    m.isdbs(static_cast<FrontendIsdbsModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::ISDBS3:
-                    m.isdbs3(static_cast<FrontendIsdbs3Modulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::ISDBT:
-                    m.isdbt(static_cast<FrontendIsdbtModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::ATSC:
-                    m.atsc(static_cast<FrontendAtscModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) FrontendType::ATSC3:
-                    m.atsc3(static_cast<FrontendAtsc3Modulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                case (int) hardware::tv::tuner::V1_1::FrontendType::DTMB:
-                    m.dtmb(static_cast<FrontendDtmbModulation>(modulation));
-                    scanMessage.modulation(m);
-                    break;
-                default:
-                    break;
-            }
-            break;
-        }
-        default:
-            break;
-    }
-    return scanMessage;
-}
-
-bool TunerFrontendCallback::is1_1ExtendedScanMessage(int messageType) {
-    return messageType >= (int)FrontendScanMessageTypeExt1_1::MODULATION
-            && messageType <= (int)FrontendScanMessageTypeExt1_1::HIGH_PRIORITY;
-}
 }  // namespace android
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 1dd950e..08c0b20 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,53 +17,29 @@
 #ifndef _ANDROID_MEDIA_TV_FRONTEND_CLIENT_H_
 #define _ANDROID_MEDIA_TV_FRONTEND_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/FrontendType.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidl/android/media/tv/tuner/BnTunerFrontendCallback.h>
 #include <aidl/android/media/tv/tuner/ITunerFrontend.h>
-#include <android/hardware/tv/tuner/1.1/IFrontend.h>
-#include <android/hardware/tv/tuner/1.1/IFrontendCallback.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
+#include <utils/RefBase.h>
 
 #include "ClientHelper.h"
 #include "FrontendClientCallback.h"
 #include "LnbClient.h"
 
 using Status = ::ndk::ScopedAStatus;
-
+using ::aidl::android::hardware::tv::tuner::FrontendEventType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessage;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanType;
+using ::aidl::android::hardware::tv::tuner::FrontendSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::BnTunerFrontendCallback;
 using ::aidl::android::media::tv::tuner::ITunerFrontend;
-using ::aidl::android::media::tv::tuner::TunerFrontendAnalogSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendAtscSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendAtsc3Settings;
-using ::aidl::android::media::tv::tuner::TunerFrontendCableSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendDvbsSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendDvbtSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendDtmbSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendIsdbsSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendIsdbs3Settings;
-using ::aidl::android::media::tv::tuner::TunerFrontendIsdbtSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendScanMessage;
-using ::aidl::android::media::tv::tuner::TunerFrontendSettings;
-using ::aidl::android::media::tv::tuner::TunerFrontendStatus;
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::tv::tuner::V1_0::FrontendInfo;
-using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
-using ::android::hardware::tv::tuner::V1_0::FrontendSettings;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatus;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
-using ::android::hardware::tv::tuner::V1_0::IFrontend;
-using ::android::hardware::tv::tuner::V1_0::Result;
-
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageTypeExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
-using ::android::hardware::tv::tuner::V1_1::IFrontendCallback;
 
 using namespace std;
 
@@ -74,32 +50,8 @@
 public:
     TunerFrontendCallback(sp<FrontendClientCallback> frontendClientCallback);
 
-    Status onEvent(int frontendEventType);
-
-    Status onScanMessage(int messageType, const TunerFrontendScanMessage& message);
-
-    void setFrontendType(int frontendType) { mType = frontendType; }
-
-private:
-    FrontendScanMessage getHalScanMessage(int messageType, const TunerFrontendScanMessage& message);
-    FrontendScanMessageExt1_1 getHalScanMessageExt1_1(int messageType,
-            const TunerFrontendScanMessage& message);
-    bool is1_1ExtendedScanMessage(int messageType);
-
-    sp<FrontendClientCallback> mFrontendClientCallback;
-    int mType;
-};
-
-struct HidlFrontendCallback : public IFrontendCallback {
-
-public:
-    HidlFrontendCallback(sp<FrontendClientCallback> frontendClientCallback);
-
-    virtual Return<void> onEvent(FrontendEventType frontendEventType);
-    virtual Return<void> onScanMessage(
-            FrontendScanMessageType type, const FrontendScanMessage& message);
-    virtual Return<void> onScanMessageExt1_1(
-            FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& messageExt);
+    Status onEvent(FrontendEventType frontendEventType);
+    Status onScanMessage(FrontendScanMessageType messageType, const FrontendScanMessage& message);
 
 private:
     sp<FrontendClientCallback> mFrontendClientCallback;
@@ -108,7 +60,7 @@
 struct FrontendClient : public RefBase {
 
 public:
-    FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend, int type);
+    FrontendClient(shared_ptr<ITunerFrontend> tunerFrontend, FrontendType type);
     ~FrontendClient();
 
     /**
@@ -116,13 +68,10 @@
      */
     Result setCallback(sp<FrontendClientCallback> frontendClientCallback);
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlFrontend(sp<IFrontend> frontend);
-
     /**
      * Tuner Frontend with Frontend Settings.
      */
-    Result tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
+    Result tune(const FrontendSettings& settings);
 
     /**
      * Stop tune Frontend.
@@ -132,8 +81,7 @@
     /**
      * Scan the frontend to use the settings given.
      */
-    Result scan(const FrontendSettings& settings, FrontendScanType frontendScanType,
-            const FrontendSettingsExt1_1& settingsExt1_1);
+    Result scan(const FrontendSettings& settings, FrontendScanType frontendScanType);
 
     /**
      * Stop the previous scanning.
@@ -146,12 +94,6 @@
     vector<FrontendStatus> getStatus(vector<FrontendStatusType> statusTypes);
 
     /**
-     * Gets the 1.1 extended statuses of the frontend.
-     */
-    vector<FrontendStatusExt1_1> getStatusExtended_1_1(
-            vector<FrontendStatusTypeExt1_1> statusTypes);
-
-    /**
      * Sets Low-Noise Block downconverter (LNB) for satellite frontend.
      */
     Result setLnb(sp<LnbClient> lnbClient);
@@ -166,68 +108,28 @@
      *
      * @return lts id
      */
-    int linkCiCamToFrontend(int ciCamId);
+    int32_t linkCiCamToFrontend(int32_t ciCamId);
 
     /**
      * Unink Frontend to the cicam with given id.
      */
-    Result unlinkCiCamToFrontend(int ciCamId);
+    Result unlinkCiCamToFrontend(int32_t ciCamId);
 
     /**
      * Close Frontend.
      */
     Result close();
 
+    int32_t getId();
     shared_ptr<ITunerFrontend> getAidlFrontend();
-
-    void setId(int id);
-    int getId();
-
 private:
-    vector<FrontendStatus> getHidlStatus(vector<TunerFrontendStatus>& aidlStatus);
-    vector<FrontendStatusExt1_1> getHidlStatusExt(vector<TunerFrontendStatus>& aidlStatus);
-
-    TunerFrontendSettings getAidlFrontendSettings(
-            const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendAnalogSettings getAidlAnalogSettings(
-            const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendDvbsSettings getAidlDvbsSettings(
-            const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendCableSettings getAidlCableSettings(
-            const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendDvbtSettings getAidlDvbtSettings(
-            const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendDtmbSettings getAidlDtmbSettings(const FrontendSettingsExt1_1& settingsExt1_1);
-    TunerFrontendAtscSettings getAidlAtscSettings(const FrontendSettings& settings);
-    TunerFrontendAtsc3Settings getAidlAtsc3Settings(const FrontendSettings& settings);
-    TunerFrontendIsdbsSettings getAidlIsdbsSettings(const FrontendSettings& settings);
-    TunerFrontendIsdbs3Settings getAidlIsdbs3Settings(const FrontendSettings& settings);
-    TunerFrontendIsdbtSettings getAidlIsdbtSettings(const FrontendSettings& settings);
-
-    bool validateExtendedSettings(const FrontendSettingsExt1_1& settingsExt1_1);
-
     /**
      * An AIDL Tuner Frontend Singleton assigned at the first time when the Tuner Client
      * opens a frontend cient. Default null when the service does not exist.
      */
     shared_ptr<ITunerFrontend> mTunerFrontend;
 
-    /**
-     * A Frontend 1.0 HAL interface as a fall back interface when the Tuner Service does not exist.
-     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
-     * Default null.
-     */
-    sp<IFrontend> mFrontend;
-
-    /**
-     * A Frontend 1.1 HAL interface as a fall back interface when the Tuner Service does not exist.
-     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
-     * Default null.
-     */
-    sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFrontend_1_1;
-
-    int mId;
-    int mType;
+    FrontendType mType;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/FrontendClientCallback.h b/media/jni/tuner/FrontendClientCallback.h
index 94f8c40..15b08ef 100644
--- a/media/jni/tuner/FrontendClientCallback.h
+++ b/media/jni/tuner/FrontendClientCallback.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,11 +17,11 @@
 #ifndef _ANDROID_MEDIA_TV_FRONTEND_CLIENT_CALLBACK_H_
 #define _ANDROID_MEDIA_TV_FRONTEND_CLIENT_CALLBACK_H_
 
-using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
-using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageExt1_1;
-using ::android::hardware::tv::tuner::V1_1::FrontendScanMessageTypeExt1_1;
+#include <utils/RefBase.h>
+
+using ::aidl::android::hardware::tv::tuner::FrontendEventType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessage;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageType;
 
 using namespace std;
 
@@ -30,8 +30,6 @@
 struct FrontendClientCallback : public RefBase {
     virtual void onEvent(FrontendEventType frontendEventType);
     virtual void onScanMessage(FrontendScanMessageType type, const FrontendScanMessage& message);
-    virtual void onScanMessageExt1_1(
-            FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& messageExt);
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/LnbClient.cpp b/media/jni/tuner/LnbClient.cpp
index 073c49a..43198e3 100644
--- a/media/jni/tuner/LnbClient.cpp
+++ b/media/jni/tuner/LnbClient.cpp
@@ -21,148 +21,89 @@
 
 #include "LnbClient.h"
 
-using ::android::hardware::tv::tuner::V1_0::Result;
-
 namespace android {
 
 /////////////// LnbClient ///////////////////////
-
 LnbClient::LnbClient(shared_ptr<ITunerLnb> tunerLnb) {
     mTunerLnb = tunerLnb;
-    mId = -1;
 }
 
 LnbClient::~LnbClient() {
-    mTunerLnb = NULL;
-    mLnb = NULL;
-    mId = -1;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-void LnbClient::setHidlLnb(sp<ILnb> lnb) {
-    mLnb = lnb;
+    mTunerLnb = nullptr;
 }
 
 Result LnbClient::setCallback(sp<LnbClientCallback> cb) {
-    if (mTunerLnb != NULL) {
+    if (mTunerLnb != nullptr) {
         shared_ptr<TunerLnbCallback> aidlCallback =
                 ::ndk::SharedRefBase::make<TunerLnbCallback>(cb);
         Status s = mTunerLnb->setCallback(aidlCallback);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        sp<HidlLnbCallback> hidlCallback = new HidlLnbCallback(cb);
-        return mLnb->setCallback(hidlCallback);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result LnbClient::setVoltage(LnbVoltage voltage) {
-    if (mTunerLnb != NULL) {
-        Status s = mTunerLnb->setVoltage((int)voltage);
+    if (mTunerLnb != nullptr) {
+        Status s = mTunerLnb->setVoltage(voltage);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        return mLnb->setVoltage(voltage);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result LnbClient::setTone(LnbTone tone) {
-    if (mTunerLnb != NULL) {
-        Status s = mTunerLnb->setTone((int)tone);
+    if (mTunerLnb != nullptr) {
+        Status s = mTunerLnb->setTone(tone);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        return mLnb->setTone(tone);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result LnbClient::setSatellitePosition(LnbPosition position) {
-    if (mTunerLnb != NULL) {
-        Status s = mTunerLnb->setSatellitePosition((int)position);
+    if (mTunerLnb != nullptr) {
+        Status s = mTunerLnb->setSatellitePosition(position);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        return mLnb->setSatellitePosition(position);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result LnbClient::sendDiseqcMessage(vector<uint8_t> diseqcMessage) {
-    if (mTunerLnb != NULL) {
+    if (mTunerLnb != nullptr) {
         Status s = mTunerLnb->sendDiseqcMessage(diseqcMessage);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        return mLnb->sendDiseqcMessage(diseqcMessage);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result LnbClient::close() {
-    if (mTunerLnb != NULL) {
+    if (mTunerLnb != nullptr) {
         Status s = mTunerLnb->close();
-        mTunerLnb = NULL;
+        mTunerLnb = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mLnb != NULL) {
-        Result res = mLnb->close();
-        mLnb = NULL;
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 
-/////////////// ILnbCallback ///////////////////////
-
-HidlLnbCallback::HidlLnbCallback(sp<LnbClientCallback> lnbClientCallback)
-        : mLnbClientCallback(lnbClientCallback) {}
-
-Return<void> HidlLnbCallback::onEvent(const LnbEventType lnbEventType) {
-    if (mLnbClientCallback != NULL) {
-        mLnbClientCallback->onEvent(lnbEventType);
-    }
-    return Void();
-}
-
-Return<void> HidlLnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
-    if (mLnbClientCallback != NULL) {
-        mLnbClientCallback->onDiseqcMessage(diseqcMessage);
-    }
-    return Void();
-}
-
 /////////////// TunerLnbCallback ///////////////////////
-
 TunerLnbCallback::TunerLnbCallback(sp<LnbClientCallback> lnbClientCallback)
         : mLnbClientCallback(lnbClientCallback) {}
 
-Status TunerLnbCallback::onEvent(int lnbEventType) {
-    if (mLnbClientCallback != NULL) {
-        mLnbClientCallback->onEvent(static_cast<LnbEventType>(lnbEventType));
+Status TunerLnbCallback::onEvent(LnbEventType lnbEventType) {
+    if (mLnbClientCallback != nullptr) {
+        mLnbClientCallback->onEvent(lnbEventType);
         return Status::ok();
     }
     return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
 }
 
 Status TunerLnbCallback::onDiseqcMessage(const vector<uint8_t>& diseqcMessage) {
-    if (mLnbClientCallback != NULL) {
-        hidl_vec<uint8_t> msg(begin(diseqcMessage), end(diseqcMessage));
-        mLnbClientCallback->onDiseqcMessage(msg);
+    if (mLnbClientCallback != nullptr) {
+        mLnbClientCallback->onDiseqcMessage(diseqcMessage);
         return Status::ok();
     }
     return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_STATE));
diff --git a/media/jni/tuner/LnbClient.h b/media/jni/tuner/LnbClient.h
index 7c6118c..86e3f67 100644
--- a/media/jni/tuner/LnbClient.h
+++ b/media/jni/tuner/LnbClient.h
@@ -17,31 +17,24 @@
 #ifndef _ANDROID_MEDIA_TV_LNB_CLIENT_H_
 #define _ANDROID_MEDIA_TV_LNB_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/LnbPosition.h>
+#include <aidl/android/hardware/tv/tuner/LnbTone.h>
+#include <aidl/android/hardware/tv/tuner/LnbVoltage.h>
 #include <aidl/android/media/tv/tuner/BnTunerLnbCallback.h>
 #include <aidl/android/media/tv/tuner/ITunerLnb.h>
-#include <android/hardware/tv/tuner/1.0/ILnb.h>
-#include <android/hardware/tv/tuner/1.0/ILnbCallback.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
+#include <utils/RefBase.h>
 
 #include "ClientHelper.h"
 #include "LnbClientCallback.h"
 
 using Status = ::ndk::ScopedAStatus;
 
+using ::aidl::android::hardware::tv::tuner::LnbPosition;
+using ::aidl::android::hardware::tv::tuner::LnbTone;
+using ::aidl::android::hardware::tv::tuner::LnbVoltage;
 using ::aidl::android::media::tv::tuner::BnTunerLnbCallback;
 using ::aidl::android::media::tv::tuner::ITunerLnb;
 
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::tv::tuner::V1_0::ILnb;
-using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
-using ::android::hardware::tv::tuner::V1_0::LnbId;
-using ::android::hardware::tv::tuner::V1_0::LnbPosition;
-using ::android::hardware::tv::tuner::V1_0::LnbTone;
-using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
-using ::android::hardware::tv::tuner::V1_0::Result;
-
 using namespace std;
 
 namespace android {
@@ -51,33 +44,19 @@
 public:
     TunerLnbCallback(sp<LnbClientCallback> lnbClientCallback);
 
-    Status onEvent(int lnbEventType);
+    Status onEvent(LnbEventType lnbEventType);
     Status onDiseqcMessage(const vector<uint8_t>& diseqcMessage);
 
 private:
     sp<LnbClientCallback> mLnbClientCallback;
 };
 
-struct HidlLnbCallback : public ILnbCallback {
-
-public:
-    HidlLnbCallback(sp<LnbClientCallback> lnbClientCallback);
-    virtual Return<void> onEvent(const LnbEventType lnbEventType);
-    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
-
-private:
-    sp<LnbClientCallback> mLnbClientCallback;
-};
-
 struct LnbClient : public RefBase {
 
 public:
     LnbClient(shared_ptr<ITunerLnb> tunerLnb);
     ~LnbClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlLnb(sp<ILnb> lnb);
-
     /**
      * Set the lnb callback.
      */
@@ -109,8 +88,6 @@
     Result close();
 
     shared_ptr<ITunerLnb> getAidlLnb() { return mTunerLnb; }
-    void setId(LnbId id) { mId = id; }
-    LnbId getId() { return mId; }
 
 private:
     /**
@@ -118,15 +95,6 @@
      * opens an Lnb. Default null when lnb is not opened.
      */
     shared_ptr<ITunerLnb> mTunerLnb;
-
-    /**
-     * A Lnb HAL interface that is ready before migrating to the TunerLnb.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<ILnb> mLnb;
-
-    LnbId mId;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/LnbClientCallback.h b/media/jni/tuner/LnbClientCallback.h
index 253d7ef..612514f 100644
--- a/media/jni/tuner/LnbClientCallback.h
+++ b/media/jni/tuner/LnbClientCallback.h
@@ -17,8 +17,9 @@
 #ifndef _ANDROID_MEDIA_TV_LNB_CLIENT_CALLBACK_H_
 #define _ANDROID_MEDIA_TV_LNB_CLIENT_CALLBACK_H_
 
-using ::android::hardware::hidl_vec;
-using ::android::hardware::tv::tuner::V1_0::LnbEventType;
+#include <utils/RefBase.h>
+
+using ::aidl::android::hardware::tv::tuner::LnbEventType;
 
 using namespace std;
 
@@ -26,8 +27,8 @@
 
 struct LnbClientCallback : public RefBase {
     virtual void onEvent(const LnbEventType lnbEventType);
-    virtual void onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+    virtual void onDiseqcMessage(const vector<uint8_t>& diseqcMessage);
 };
 }  // namespace android
 
-#endif  // _ANDROID_MEDIA_TV_LNB_CLIENT_CALLBACK_H_
\ No newline at end of file
+#endif // _ANDROID_MEDIA_TV_LNB_CLIENT_CALLBACK_H_
diff --git a/media/jni/tuner/TimeFilterClient.cpp b/media/jni/tuner/TimeFilterClient.cpp
index e123c9f..40dba8b 100644
--- a/media/jni/tuner/TimeFilterClient.cpp
+++ b/media/jni/tuner/TimeFilterClient.cpp
@@ -16,14 +16,15 @@
 
 #define LOG_TAG "TimeFilterClient"
 
+#include "TimeFilterClient.h"
+
+#include <aidl/android/hardware/tv/tuner/Constant64Bit.h>
 #include <android-base/logging.h>
 #include <utils/Log.h>
 
 #include "ClientHelper.h"
-#include "TimeFilterClient.h"
 
-using ::android::hardware::tv::tuner::V1_0::Result;
-using ::android::hardware::tv::tuner::V1_1::Constant64Bit;
+using ::aidl::android::hardware::tv::tuner::Constant64Bit;
 
 namespace android {
 
@@ -34,108 +35,60 @@
 }
 
 TimeFilterClient::~TimeFilterClient() {
-    mTunerTimeFilter = NULL;
-    mTimeFilter = NULL;
+    mTunerTimeFilter = nullptr;
 }
 
-// TODO: remove after migration to Tuner Service is done.
-void TimeFilterClient::setHidlTimeFilter(sp<ITimeFilter> timeFilter) {
-    mTimeFilter = timeFilter;
-}
-
-Result TimeFilterClient::setTimeStamp(long timeStamp) {
-    if (mTunerTimeFilter != NULL) {
+Result TimeFilterClient::setTimeStamp(int64_t timeStamp) {
+    if (mTunerTimeFilter != nullptr) {
         Status s = mTunerTimeFilter->setTimeStamp(timeStamp);
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mTimeFilter != NULL) {
-        return mTimeFilter->setTimeStamp(timeStamp);
-    }
-
     return Result::INVALID_STATE;
 }
 
 Result TimeFilterClient::clearTimeStamp() {
-    if (mTunerTimeFilter != NULL) {
+    if (mTunerTimeFilter != nullptr) {
         Status s = mTunerTimeFilter->clearTimeStamp();
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mTimeFilter != NULL) {
-        return mTimeFilter->clearTimeStamp();
-    }
-
     return Result::INVALID_STATE;
 }
 
-long TimeFilterClient::getTimeStamp() {
-    if (mTunerTimeFilter != NULL) {
+int64_t TimeFilterClient::getTimeStamp() {
+    if (mTunerTimeFilter != nullptr) {
         int64_t timeStamp;
         Status s = mTunerTimeFilter->getTimeStamp(&timeStamp);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        if (!s.isOk()) {
+            return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
         }
         return timeStamp;
     }
 
-    if (mTimeFilter != NULL) {
-        Result res;
-        long timestamp;
-        mTimeFilter->getTimeStamp(
-                [&](Result r, uint64_t t) {
-                    res = r;
-                    timestamp = t;
-                });
-        if (res != Result::SUCCESS) {
-            return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
-        }
-        return timestamp;
-    }
-
-    return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+    return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
 }
 
-long TimeFilterClient::getSourceTime() {
-    if (mTunerTimeFilter != NULL) {
+int64_t TimeFilterClient::getSourceTime() {
+    if (mTunerTimeFilter != nullptr) {
         int64_t sourceTime;
         Status s = mTunerTimeFilter->getTimeStamp(&sourceTime);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        if (!s.isOk()) {
+            return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
         }
         return sourceTime;
     }
 
-    if (mTimeFilter != NULL) {
-        Result res;
-        long sourceTime;
-        mTimeFilter->getSourceTime(
-                [&](Result r, uint64_t t) {
-                    res = r;
-                    sourceTime = t;
-                });
-        if (res != Result::SUCCESS) {
-            return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
-        }
-        return sourceTime;
-    }
-
-    return (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+    return static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
 }
 
 Result TimeFilterClient::close() {
-    if (mTunerTimeFilter != NULL) {
+    if (mTunerTimeFilter != nullptr) {
         Status s = mTunerTimeFilter->close();
-        mTunerTimeFilter = NULL;
+        mTunerTimeFilter = nullptr;
         return ClientHelper::getServiceSpecificErrorCode(s);
     }
 
-    if (mTimeFilter != NULL) {
-        Result res = mTimeFilter->close();
-        mTimeFilter = NULL;
-        return res;
-    }
-
     return Result::INVALID_STATE;
 }
 }  // namespace android
diff --git a/media/jni/tuner/TimeFilterClient.h b/media/jni/tuner/TimeFilterClient.h
index 56ddd68..46f33be 100644
--- a/media/jni/tuner/TimeFilterClient.h
+++ b/media/jni/tuner/TimeFilterClient.h
@@ -17,18 +17,14 @@
 #ifndef _ANDROID_MEDIA_TV_TIME_FILTER_CLIENT_H_
 #define _ANDROID_MEDIA_TV_TIME_FILTER_CLIENT_H_
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
 #include <aidl/android/media/tv/tuner/ITunerTimeFilter.h>
-#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
-
-using ::aidl::android::media::tv::tuner::ITunerTimeFilter;
+#include <utils/RefBase.h>
 
 using Status = ::ndk::ScopedAStatus;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::tv::tuner::V1_0::ITimeFilter;
-using ::android::hardware::tv::tuner::V1_0::Result;
+
+using ::aidl::android::hardware::tv::tuner::Result;
+using ::aidl::android::media::tv::tuner::ITunerTimeFilter;
 
 using namespace std;
 
@@ -40,13 +36,10 @@
     TimeFilterClient(shared_ptr<ITunerTimeFilter> tunerTimeFilter);
     ~TimeFilterClient();
 
-    // TODO: remove after migration to Tuner Service is done.
-    void setHidlTimeFilter(sp<ITimeFilter> timeFilter);
-
     /**
      * Set time stamp for time based filter.
      */
-    Result setTimeStamp(long timeStamp);
+    Result setTimeStamp(int64_t timeStamp);
 
     /**
      * Clear the time stamp in the time filter.
@@ -56,12 +49,12 @@
     /**
      * Get the current time in the time filter.
      */
-    long getTimeStamp();
+    int64_t getTimeStamp();
 
     /**
      * Get the time from the beginning of current data source.
      */
-    long getSourceTime();
+    int64_t getSourceTime();
 
     /**
      * Releases the Time Filter instance.
@@ -74,13 +67,6 @@
      * opens an TimeFilter. Default null when time filter is not opened.
      */
     shared_ptr<ITunerTimeFilter> mTunerTimeFilter;
-
-    /**
-     * A TimeFilter HAL interface that is ready before migrating to the TunerTimeFilter.
-     * This is a temprary interface before Tuner Framework migrates to use TunerService.
-     * Default null when the HAL service does not exist.
-     */
-    sp<ITimeFilter> mTimeFilter;
 };
 }  // namespace android
 
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index e05dba6..d19ee0d4 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,31 +22,20 @@
 
 #include "TunerClient.h"
 
-using ::aidl::android::media::tv::tuner::TunerFrontendCapabilities;
-using ::aidl::android::media::tv::tuner::TunerFrontendDtmbCapabilities;
-using ::android::hardware::tv::tuner::V1_0::FrontendId;
-using ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
-using ::android::hardware::tv::tuner::V1_0::FrontendType;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
 
 namespace android {
 
-sp<ITuner> TunerClient::mTuner;
-sp<::android::hardware::tv::tuner::V1_1::ITuner> TunerClient::mTuner_1_1;
 shared_ptr<ITunerService> TunerClient::mTunerService;
-int TunerClient::mTunerVersion;
+int32_t TunerClient::mTunerVersion;
 
 /////////////// TunerClient ///////////////////////
 
 TunerClient::TunerClient() {
-    // Get HIDL Tuner in migration stage.
-    getHidlTuner();
-    if (mTuner != NULL) {
-        updateTunerResources();
-    }
-    // Connect with Tuner Service.
     ::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner"));
     mTunerService = ITunerService::fromBinder(binder);
-    if (mTunerService == NULL) {
+    if (mTunerService == nullptr) {
         ALOGE("Failed to get tuner service");
     } else {
         mTunerService->getTunerHalVersion(&mTunerVersion);
@@ -54,575 +43,124 @@
 }
 
 TunerClient::~TunerClient() {
-    mTuner = NULL;
-    mTuner_1_1 = NULL;
     mTunerVersion = 0;
-    mTunerService = NULL;
+    mTunerService = nullptr;
 }
 
-vector<FrontendId> TunerClient::getFrontendIds() {
-    vector<FrontendId> ids;
+vector<int32_t> TunerClient::getFrontendIds() {
+    vector<int32_t> ids;
 
-    if (mTunerService != NULL) {
-        vector<int32_t> v;
-        Status s = mTunerService->getFrontendIds(&v);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS || v.size() == 0) {
+    if (mTunerService != nullptr) {
+        Status s = mTunerService->getFrontendIds(&ids);
+        if (!s.isOk()) {
             ids.clear();
-            return ids;
         }
-        for (int32_t id : v) {
-            ids.push_back(static_cast<FrontendId>(id));
-        }
-        return ids;
-    }
-
-    if (mTuner != NULL) {
-        Result res;
-        mTuner->getFrontendIds([&](Result r, const hardware::hidl_vec<FrontendId>& frontendIds) {
-            res = r;
-            ids = frontendIds;
-        });
-        if (res != Result::SUCCESS || ids.size() == 0) {
-            ALOGW("Frontend ids not available");
-            ids.clear();
-            return ids;
-        }
-        return ids;
     }
 
     return ids;
 }
 
-
-sp<FrontendClient> TunerClient::openFrontend(int frontendHandle) {
-    if (mTunerService != NULL) {
+sp<FrontendClient> TunerClient::openFrontend(int32_t frontendHandle) {
+    if (mTunerService != nullptr) {
         shared_ptr<ITunerFrontend> tunerFrontend;
         Status s = mTunerService->openFrontend(frontendHandle, &tunerFrontend);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS
-                || tunerFrontend == NULL) {
-            return NULL;
+        if (!s.isOk() || tunerFrontend == nullptr) {
+            return nullptr;
         }
-        int id;
+        int32_t id;
         s = tunerFrontend->getFrontendId(&id);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            tunerFrontend->close();
+            return nullptr;
         }
-        TunerFrontendInfo aidlFrontendInfo;
-        s = mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        FrontendInfo frontendInfo;
+        s = mTunerService->getFrontendInfo(id, &frontendInfo);
+        if (!s.isOk()) {
+            tunerFrontend->close();
+            return nullptr;
         }
-        return new FrontendClient(tunerFrontend, aidlFrontendInfo.type);
+        return new FrontendClient(tunerFrontend, frontendInfo.type);
     }
 
-    if (mTuner != NULL) {
-        int id = getResourceIdFromHandle(frontendHandle, FRONTEND);
-        sp<IFrontend> hidlFrontend = openHidlFrontendById(id);
-        if (hidlFrontend != NULL) {
-            FrontendInfo hidlInfo;
-            Result res = getHidlFrontendInfo(id, hidlInfo);
-            if (res != Result::SUCCESS) {
-                return NULL;
-            }
-            sp<FrontendClient> frontendClient = new FrontendClient(
-                    NULL, (int)hidlInfo.type);
-            frontendClient->setHidlFrontend(hidlFrontend);
-            frontendClient->setId(id);
-            return frontendClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int id) {
-    if (mTunerService != NULL) {
-        TunerFrontendInfo aidlFrontendInfo;
+shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int32_t id) {
+    if (mTunerService != nullptr) {
+        FrontendInfo aidlFrontendInfo;
         Status s = mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
-        return make_shared<FrontendInfo>(frontendInfoAidlToHidl(aidlFrontendInfo));
+        return make_shared<FrontendInfo>(aidlFrontendInfo);
     }
 
-    if (mTuner != NULL) {
-        FrontendInfo hidlInfo;
-        Result res = getHidlFrontendInfo(id, hidlInfo);
-        if (res != Result::SUCCESS) {
-            return NULL;
-        }
-        return make_shared<FrontendInfo>(hidlInfo);
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-shared_ptr<FrontendDtmbCapabilities> TunerClient::getFrontendDtmbCapabilities(int id) {
-    if (mTunerService != NULL) {
-        TunerFrontendDtmbCapabilities dtmbCaps;
-        Status s = mTunerService->getFrontendDtmbCapabilities(id, &dtmbCaps);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
-        }
-        FrontendDtmbCapabilities hidlCaps{
-            .transmissionModeCap = static_cast<uint32_t>(dtmbCaps.transmissionModeCap),
-            .bandwidthCap = static_cast<uint32_t>(dtmbCaps.bandwidthCap),
-            .modulationCap = static_cast<uint32_t>(dtmbCaps.modulationCap),
-            .codeRateCap = static_cast<uint32_t>(dtmbCaps.codeRateCap),
-            .guardIntervalCap = static_cast<uint32_t>(dtmbCaps.guardIntervalCap),
-            .interleaveModeCap = static_cast<uint32_t>(dtmbCaps.interleaveModeCap),
-        };
-        return make_shared<FrontendDtmbCapabilities>(hidlCaps);
-    }
-
-    if (mTuner_1_1 != NULL) {
-        Result result;
-        FrontendDtmbCapabilities dtmbCaps;
-        mTuner_1_1->getFrontendDtmbCapabilities(id,
-                [&](Result r, const FrontendDtmbCapabilities& caps) {
-            dtmbCaps = caps;
-            result = r;
-        });
-        if (result == Result::SUCCESS) {
-            return make_shared<FrontendDtmbCapabilities>(dtmbCaps);
-        }
-    }
-
-    return NULL;
-}
-
-sp<DemuxClient> TunerClient::openDemux(int demuxHandle) {
-    if (mTunerService != NULL) {
+sp<DemuxClient> TunerClient::openDemux(int32_t demuxHandle) {
+    if (mTunerService != nullptr) {
         shared_ptr<ITunerDemux> tunerDemux;
         Status s = mTunerService->openDemux(demuxHandle, &tunerDemux);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new DemuxClient(tunerDemux);
     }
 
-    if (mTuner != NULL) {
-        sp<DemuxClient> demuxClient = new DemuxClient(NULL);
-        int demuxId;
-        sp<IDemux> hidlDemux = openHidlDemux(demuxId);
-        if (hidlDemux != NULL) {
-            demuxClient->setHidlDemux(hidlDemux);
-            demuxClient->setId(demuxId);
-            return demuxClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
 shared_ptr<DemuxCapabilities> TunerClient::getDemuxCaps() {
-    if (mTunerService != NULL) {
-        TunerDemuxCapabilities aidlCaps;
+    if (mTunerService != nullptr) {
+        DemuxCapabilities aidlCaps;
         Status s = mTunerService->getDemuxCaps(&aidlCaps);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
-        return make_shared<DemuxCapabilities>(getHidlDemuxCaps(aidlCaps));
+        return make_shared<DemuxCapabilities>(aidlCaps);
     }
 
-    if (mTuner != NULL) {
-        Result res;
-        DemuxCapabilities caps;
-        mTuner->getDemuxCaps([&](Result r, const DemuxCapabilities& demuxCaps) {
-            caps = demuxCaps;
-            res = r;
-        });
-        if (res == Result::SUCCESS) {
-            return make_shared<DemuxCapabilities>(caps);
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-sp<DescramblerClient> TunerClient::openDescrambler(int descramblerHandle) {
-    if (mTunerService != NULL) {
+sp<DescramblerClient> TunerClient::openDescrambler(int32_t descramblerHandle) {
+    if (mTunerService != nullptr) {
         shared_ptr<ITunerDescrambler> tunerDescrambler;
         Status s = mTunerService->openDescrambler(descramblerHandle, &tunerDescrambler);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new DescramblerClient(tunerDescrambler);
     }
 
-    if (mTuner != NULL) {
-        sp<DescramblerClient> descramblerClient = new DescramblerClient(NULL);
-        sp<IDescrambler> hidlDescrambler = openHidlDescrambler();
-        if (hidlDescrambler != NULL) {
-            descramblerClient->setHidlDescrambler(hidlDescrambler);
-            return descramblerClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-sp<LnbClient> TunerClient::openLnb(int lnbHandle) {
-    if (mTunerService != NULL) {
+sp<LnbClient> TunerClient::openLnb(int32_t lnbHandle) {
+    if (mTunerService != nullptr) {
         shared_ptr<ITunerLnb> tunerLnb;
         Status s = mTunerService->openLnb(lnbHandle, &tunerLnb);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new LnbClient(tunerLnb);
     }
 
-    if (mTuner != NULL) {
-        int id = getResourceIdFromHandle(lnbHandle, LNB);
-        sp<LnbClient> lnbClient = new LnbClient(NULL);
-        sp<ILnb> hidlLnb = openHidlLnbById(id);
-        if (hidlLnb != NULL) {
-            lnbClient->setHidlLnb(hidlLnb);
-            lnbClient->setId(id);
-            return lnbClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
 sp<LnbClient> TunerClient::openLnbByName(string lnbName) {
-    if (mTunerService != NULL) {
+    if (mTunerService != nullptr) {
         shared_ptr<ITunerLnb> tunerLnb;
         Status s = mTunerService->openLnbByName(lnbName, &tunerLnb);
-        if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
-            return NULL;
+        if (!s.isOk()) {
+            return nullptr;
         }
         return new LnbClient(tunerLnb);
     }
 
-    if (mTuner != NULL) {
-        sp<LnbClient> lnbClient = new LnbClient(NULL);
-        LnbId id;
-        sp<ILnb> hidlLnb = openHidlLnbByName(lnbName, id);
-        if (hidlLnb != NULL) {
-            lnbClient->setHidlLnb(hidlLnb);
-            lnbClient->setId(id);
-            return lnbClient;
-        }
-    }
-
-    return NULL;
+    return nullptr;
 }
 
-/////////////// TunerClient Helper Methods ///////////////////////
-
-void TunerClient::updateTunerResources() {
-    if (mTuner == NULL) {
-        return;
-    }
-
-    // Connect with Tuner Resource Manager.
-    ::ndk::SpAIBinder binder(AServiceManager_getService("tv_tuner_resource_mgr"));
-    mTunerResourceManager = ITunerResourceManager::fromBinder(binder);
-
-    updateFrontendResources();
-    updateLnbResources();
-    // TODO: update Demux, Descrambler.
-}
-
-// TODO: remove after migration to Tuner Service is done.
-void TunerClient::updateFrontendResources() {
-    vector<FrontendId> ids = getFrontendIds();
-    if (ids.size() == 0) {
-        return;
-    }
-    vector<TunerFrontendInfo> infos;
-    for (int i = 0; i < ids.size(); i++) {
-        shared_ptr<FrontendInfo> frontendInfo = getFrontendInfo((int)ids[i]);
-        if (frontendInfo == NULL) {
-            continue;
-        }
-        TunerFrontendInfo tunerFrontendInfo{
-            .handle = getResourceHandleFromId((int)ids[i], FRONTEND),
-            .type = static_cast<int>(frontendInfo->type),
-            .exclusiveGroupId = static_cast<int>(frontendInfo->exclusiveGroupId),
-        };
-        infos.push_back(tunerFrontendInfo);
-    }
-    mTunerResourceManager->setFrontendInfoList(infos);
-}
-
-void TunerClient::updateLnbResources() {
-    vector<int> handles = getLnbHandles();
-    if (handles.size() == 0) {
-        return;
-    }
-    mTunerResourceManager->setLnbInfoList(handles);
-}
-
-sp<ITuner> TunerClient::getHidlTuner() {
-    if (mTuner == NULL) {
-        mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
-        mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::getService();
-
-        if (mTuner_1_1 == NULL) {
-            ALOGW("Failed to get tuner 1.1 service.");
-            mTuner = ITuner::getService();
-            if (mTuner == NULL) {
-                ALOGW("Failed to get tuner 1.0 service.");
-            } else {
-                mTunerVersion = TUNER_HAL_VERSION_1_0;
-            }
-        } else {
-            mTuner = static_cast<sp<ITuner>>(mTuner_1_1);
-            mTunerVersion = TUNER_HAL_VERSION_1_1;
-         }
-     }
-     return mTuner;
-}
-
-sp<IFrontend> TunerClient::openHidlFrontendById(int id) {
-    sp<IFrontend> fe;
-    Result res;
-    mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) {
-        fe = frontend;
-        res = r;
-    });
-    if (res != Result::SUCCESS || fe == nullptr) {
-        ALOGE("Failed to open frontend");
-        return NULL;
-    }
-    return fe;
-}
-
-Result TunerClient::getHidlFrontendInfo(int id, FrontendInfo& feInfo) {
-    Result res;
-    mTuner->getFrontendInfo(id, [&](Result r, const FrontendInfo& info) {
-        feInfo = info;
-        res = r;
-    });
-    return res;
-}
-
-sp<IDemux> TunerClient::openHidlDemux(int& demuxId) {
-    sp<IDemux> demux;
-    Result res;
-
-    mTuner->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) {
-        demux = demuxSp;
-        demuxId = id;
-        res = result;
-    });
-    if (res != Result::SUCCESS || demux == nullptr) {
-        ALOGE("Failed to open demux");
-        return NULL;
-    }
-    return demux;
-}
-
-sp<ILnb> TunerClient::openHidlLnbById(int id) {
-    sp<ILnb> lnb;
-    Result res;
-
-    mTuner->openLnbById(id, [&](Result r, const sp<ILnb>& lnbSp) {
-        res = r;
-        lnb = lnbSp;
-    });
-    if (res != Result::SUCCESS || lnb == nullptr) {
-        ALOGE("Failed to open lnb by id");
-        return NULL;
-    }
-    return lnb;
-}
-
-sp<ILnb> TunerClient::openHidlLnbByName(string name, LnbId& lnbId) {
-    sp<ILnb> lnb;
-    Result res;
-
-    mTuner->openLnbByName(name, [&](Result r, LnbId id, const sp<ILnb>& lnbSp) {
-        res = r;
-        lnb = lnbSp;
-        lnbId = id;
-    });
-    if (res != Result::SUCCESS || lnb == nullptr) {
-        ALOGE("Failed to open lnb by name");
-        return NULL;
-    }
-    return lnb;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-vector<int> TunerClient::getLnbHandles() {
-    vector<int> lnbHandles;
-    if (mTuner != NULL) {
-        Result res;
-        vector<LnbId> lnbIds;
-        mTuner->getLnbIds([&](Result r, const hardware::hidl_vec<LnbId>& ids) {
-            lnbIds = ids;
-            res = r;
-        });
-        if (res != Result::SUCCESS || lnbIds.size() == 0) {
-            ALOGW("Lnb isn't available");
-        } else {
-            for (int i = 0; i < lnbIds.size(); i++) {
-                lnbHandles.push_back(getResourceHandleFromId((int)lnbIds[i], LNB));
-            }
-        }
-    }
-
-    return lnbHandles;
-}
-
-sp<IDescrambler> TunerClient::openHidlDescrambler() {
-    sp<IDescrambler> descrambler;
-    Result res;
-
-    mTuner->openDescrambler([&](Result r, const sp<IDescrambler>& descramblerSp) {
-        res = r;
-        descrambler = descramblerSp;
-    });
-
-    if (res != Result::SUCCESS || descrambler == NULL) {
-        return NULL;
-    }
-
-    return descrambler;
-}
-
-DemuxCapabilities TunerClient::getHidlDemuxCaps(TunerDemuxCapabilities& aidlCaps) {
-    DemuxCapabilities caps{
-        .numDemux = (uint32_t)aidlCaps.numDemux,
-        .numRecord = (uint32_t)aidlCaps.numRecord,
-        .numPlayback = (uint32_t)aidlCaps.numPlayback,
-        .numTsFilter = (uint32_t)aidlCaps.numTsFilter,
-        .numSectionFilter = (uint32_t)aidlCaps.numSectionFilter,
-        .numAudioFilter = (uint32_t)aidlCaps.numAudioFilter,
-        .numVideoFilter = (uint32_t)aidlCaps.numVideoFilter,
-        .numPesFilter = (uint32_t)aidlCaps.numPesFilter,
-        .numPcrFilter = (uint32_t)aidlCaps.numPcrFilter,
-        .numBytesInSectionFilter = (uint32_t)aidlCaps.numBytesInSectionFilter,
-        .filterCaps = (uint32_t)aidlCaps.filterCaps,
-        .bTimeFilter = aidlCaps.bTimeFilter,
-    };
-    caps.linkCaps.resize(aidlCaps.linkCaps.size());
-    copy(aidlCaps.linkCaps.begin(), aidlCaps.linkCaps.end(), caps.linkCaps.begin());
-    return caps;
-}
-
-FrontendInfo TunerClient::frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo) {
-    FrontendInfo hidlFrontendInfo {
-        .type = static_cast<FrontendType>(aidlFrontendInfo.type),
-        .minFrequency = static_cast<uint32_t>(aidlFrontendInfo.minFrequency),
-        .maxFrequency = static_cast<uint32_t>(aidlFrontendInfo.maxFrequency),
-        .minSymbolRate = static_cast<uint32_t>(aidlFrontendInfo.minSymbolRate),
-        .maxSymbolRate = static_cast<uint32_t>(aidlFrontendInfo.maxSymbolRate),
-        .acquireRange = static_cast<uint32_t>(aidlFrontendInfo.acquireRange),
-        .exclusiveGroupId = static_cast<uint32_t>(aidlFrontendInfo.exclusiveGroupId),
-    };
-
-    int size = aidlFrontendInfo.statusCaps.size();
-    hidlFrontendInfo.statusCaps.resize(size);
-    for (int i = 0; i < size; i++) {
-        hidlFrontendInfo.statusCaps[i] =
-                static_cast<FrontendStatusType>(aidlFrontendInfo.statusCaps[i]);
-    }
-
-    switch (aidlFrontendInfo.caps.getTag()) {
-        case TunerFrontendCapabilities::analogCaps: {
-            auto analog = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::analogCaps>();
-            hidlFrontendInfo.frontendCaps.analogCaps({
-                .typeCap = static_cast<uint32_t>(analog.typeCap),
-                .sifStandardCap = static_cast<uint32_t>(analog.sifStandardCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::atscCaps: {
-            auto atsc = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::atscCaps>();
-            hidlFrontendInfo.frontendCaps.atscCaps({
-                .modulationCap = static_cast<uint32_t>(atsc.modulationCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::atsc3Caps: {
-            auto atsc3 = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::atsc3Caps>();
-            hidlFrontendInfo.frontendCaps.atsc3Caps({
-                .bandwidthCap = static_cast<uint32_t>(atsc3.bandwidthCap),
-                .modulationCap = static_cast<uint32_t>(atsc3.modulationCap),
-                .timeInterleaveModeCap = static_cast<uint32_t>(atsc3.timeInterleaveModeCap),
-                .codeRateCap = static_cast<uint32_t>(atsc3.codeRateCap),
-                .fecCap = static_cast<uint32_t>(atsc3.fecCap),
-                .demodOutputFormatCap = static_cast<uint8_t>(atsc3.demodOutputFormatCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::cableCaps: {
-            auto cable = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::cableCaps>();
-            hidlFrontendInfo.frontendCaps.dvbcCaps({
-                .modulationCap = static_cast<uint32_t>(cable.modulationCap),
-                .fecCap = static_cast<uint64_t>(cable.codeRateCap),
-                .annexCap = static_cast<uint8_t>(cable.annexCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::dvbsCaps: {
-            auto dvbs = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::dvbsCaps>();
-            hidlFrontendInfo.frontendCaps.dvbsCaps({
-                .modulationCap = static_cast<int32_t>(dvbs.modulationCap),
-                .innerfecCap = static_cast<uint64_t>(dvbs.codeRateCap),
-                .standard = static_cast<uint8_t>(dvbs.standard),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::dvbtCaps: {
-            auto dvbt = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::dvbtCaps>();
-            hidlFrontendInfo.frontendCaps.dvbtCaps({
-                .transmissionModeCap = static_cast<uint32_t>(dvbt.transmissionModeCap),
-                .bandwidthCap = static_cast<uint32_t>(dvbt.bandwidthCap),
-                .constellationCap = static_cast<uint32_t>(dvbt.constellationCap),
-                .coderateCap = static_cast<uint32_t>(dvbt.codeRateCap),
-                .hierarchyCap = static_cast<uint32_t>(dvbt.hierarchyCap),
-                .guardIntervalCap = static_cast<uint32_t>(dvbt.guardIntervalCap),
-                .isT2Supported = dvbt.isT2Supported,
-                .isMisoSupported = dvbt.isMisoSupported,
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::isdbsCaps: {
-            auto isdbs = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbsCaps>();
-            hidlFrontendInfo.frontendCaps.isdbsCaps({
-                .modulationCap = static_cast<uint32_t>(isdbs.modulationCap),
-                .coderateCap = static_cast<uint32_t>(isdbs.codeRateCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::isdbs3Caps: {
-            auto isdbs3 = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbs3Caps>();
-            hidlFrontendInfo.frontendCaps.isdbs3Caps({
-                .modulationCap = static_cast<uint32_t>(isdbs3.modulationCap),
-                .coderateCap = static_cast<uint32_t>(isdbs3.codeRateCap),
-            });
-            break;
-        }
-        case TunerFrontendCapabilities::isdbtCaps: {
-            auto isdbt = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbtCaps>();
-            hidlFrontendInfo.frontendCaps.isdbtCaps({
-                .modeCap = static_cast<uint32_t>(isdbt.modeCap),
-                .bandwidthCap = static_cast<uint32_t>(isdbt.bandwidthCap),
-                .modulationCap = static_cast<uint32_t>(isdbt.modulationCap),
-                .coderateCap = static_cast<uint32_t>(isdbt.codeRateCap),
-                .guardIntervalCap = static_cast<uint32_t>(isdbt.guardIntervalCap),
-            });
-            break;
-        }
-    }
-    return hidlFrontendInfo;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-int TunerClient::getResourceIdFromHandle(int handle, int /*resourceType*/) {
-    return (handle & 0x00ff0000) >> 16;
-}
-
-// TODO: remove after migration to Tuner Service is done.
-int TunerClient::getResourceHandleFromId(int id, int resourceType) {
-    return (resourceType & 0x000000ff) << 24
-            | (id << 16)
-            | (mResourceRequestCount++ & 0xffff);
-}
 }  // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 9671cf7..641f106 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,12 +17,8 @@
 #ifndef _ANDROID_MEDIA_TV_TUNER_CLIENT_H_
 #define _ANDROID_MEDIA_TV_TUNER_CLIENT_H_
 
-#include <aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.h>
 #include <aidl/android/media/tv/tuner/ITunerService.h>
-#include <aidl/android/media/tv/tuner/TunerFrontendInfo.h>
 #include <android/binder_parcel_utils.h>
-#include <android/hardware/tv/tuner/1.1/ITuner.h>
-#include <android/hardware/tv/tuner/1.1/types.h>
 
 #include "DemuxClient.h"
 #include "ClientHelper.h"
@@ -32,32 +28,19 @@
 
 using Status = ::ndk::ScopedAStatus;
 
-using ::aidl::android::media::tv::tuner::TunerDemuxCapabilities;
+using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::hardware::tv::tuner::Result;
 using ::aidl::android::media::tv::tuner::ITunerService;
-using ::aidl::android::media::tv::tuner::TunerFrontendInfo;
-using ::aidl::android::media::tv::tunerresourcemanager::ITunerResourceManager;
-
-using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
-using ::android::hardware::tv::tuner::V1_0::FrontendId;
-using ::android::hardware::tv::tuner::V1_0::ITuner;
-using ::android::hardware::tv::tuner::V1_0::LnbId;
-using ::android::hardware::tv::tuner::V1_0::Result;
-using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities;
 
 using namespace std;
 
 namespace android {
 
-const static int TUNER_HAL_VERSION_UNKNOWN = 0;
-const static int TUNER_HAL_VERSION_1_0 = 1 << 16;
-const static int TUNER_HAL_VERSION_1_1 = (1 << 16) | 1;
-
-typedef enum {
-    FRONTEND,
-    LNB,
-    DEMUX,
-    DESCRAMBLER,
-} TunerResourceType;
+const static int32_t TUNER_HAL_VERSION_UNKNOWN = 0;
+const static int32_t TUNER_HAL_VERSION_1_0 = 1 << 16;
+const static int32_t TUNER_HAL_VERSION_1_1 = (1 << 16) | 1;
+const static int32_t TUNER_HAL_VERSION_2_0 = 2 << 16;
 
 struct TunerClient : public RefBase {
 
@@ -70,7 +53,7 @@
      *
      * @return a list of the available frontend ids
      */
-    vector<FrontendId> getFrontendIds();
+    vector<int32_t> getFrontendIds();
 
     /**
      * Open a new interface of FrontendClient given a frontendHandle.
@@ -78,7 +61,7 @@
      * @param frontendHandle the handle of the frontend granted by TRM.
      * @return a newly created FrontendClient interface.
      */
-    sp<FrontendClient> openFrontend(int frontendHandle);
+    sp<FrontendClient> openFrontend(int32_t frontendHandle);
 
     /**
      * Retrieve the granted frontend's information.
@@ -86,15 +69,7 @@
      * @param id the id of the frontend granted by TRM.
      * @return the information for the frontend.
      */
-    shared_ptr<FrontendInfo> getFrontendInfo(int id);
-
-    /**
-     * Retrieve the DTMB frontend's capabilities.
-     *
-     * @param id the id of the DTMB frontend.
-     * @return the capabilities of the frontend.
-     */
-    shared_ptr<FrontendDtmbCapabilities> getFrontendDtmbCapabilities(int id);
+    shared_ptr<FrontendInfo> getFrontendInfo(int32_t id);
 
     /**
      * Open a new interface of DemuxClient given a demuxHandle.
@@ -102,7 +77,7 @@
      * @param demuxHandle the handle of the demux granted by TRM.
      * @return a newly created DemuxClient interface.
      */
-    sp<DemuxClient> openDemux(int demuxHandle);
+    sp<DemuxClient> openDemux(int32_t demuxHandle);
 
     /**
      * Retrieve the Demux capabilities.
@@ -117,7 +92,7 @@
      * @param descramblerHandle the handle of the descrambler granted by TRM.
      * @return a newly created DescramblerClient interface.
      */
-    sp<DescramblerClient> openDescrambler(int descramblerHandle);
+    sp<DescramblerClient> openDescrambler(int32_t descramblerHandle);
 
     /**
      * Open a new interface of LnbClient given an lnbHandle.
@@ -125,7 +100,7 @@
      * @param lnbHandle the handle of the LNB granted by TRM.
      * @return a newly created LnbClient interface.
      */
-    sp<LnbClient> openLnb(int lnbHandle);
+    sp<LnbClient> openLnb(int32_t lnbHandle);
 
     /**
      * Open a new interface of LnbClient given a LNB name.
@@ -139,54 +114,18 @@
      * Get the current Tuner HAL version. The high 16 bits are the major version number
      * while the low 16 bits are the minor version. Default value is unknown version 0.
      */
-    int getHalTunerVersion() { return mTunerVersion; }
+    int32_t getHalTunerVersion() { return mTunerVersion; }
 
 private:
-    sp<ITuner> getHidlTuner();
-    sp<IFrontend> openHidlFrontendById(int id);
-    sp<IDemux> openHidlDemux(int& demuxId);
-    Result getHidlFrontendInfo(int id, FrontendInfo& info);
-    sp<ILnb> openHidlLnbById(int id);
-    sp<ILnb> openHidlLnbByName(string name, LnbId& lnbId);
-    sp<IDescrambler> openHidlDescrambler();
-    vector<int> getLnbHandles();
-    DemuxCapabilities getHidlDemuxCaps(TunerDemuxCapabilities& aidlCaps);
-    FrontendInfo frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo);
-    void updateTunerResources();
-    void updateFrontendResources();
-    void updateLnbResources();
-
-    int getResourceIdFromHandle(int handle, int resourceType);
-
-    int getResourceHandleFromId(int id, int resourceType);
-
     /**
      * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client
      * connects with the Tuner Service. Default null when the service does not exist.
      */
     static shared_ptr<ITunerService> mTunerService;
 
-    /**
-     * A Tuner 1.0 HAL interface that is ready before connecting to the TunerService
-     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
-     * Default null.
-     */
-    static sp<ITuner> mTuner;
-
-    /**
-     * A Tuner 1.1 HAL interface that is ready before connecting to the TunerService
-     * This is a temprary connection before the Tuner Framework fully migrates to the TunerService.
-     * Default null.
-     */
-    static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
-
     // An integer that carries the Tuner version. The high 16 bits are the major version number
     // while the low 16 bits are the minor version. Default value is unknown version 0.
-    static int mTunerVersion;
-
-    shared_ptr<ITunerResourceManager> mTunerResourceManager;
-
-    int mResourceRequestCount = 0;
+    static int32_t mTunerVersion;
 };
 }  // namespace android
 
diff --git a/mms/OWNERS b/mms/OWNERS
index befc320..7f05a2a 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -2,7 +2,6 @@
 
 tgunn@google.com
 breadley@google.com
-hallliu@google.com
 rgreenwalt@google.com
 amitmahajan@google.com
 fionaxu@google.com
@@ -10,7 +9,10 @@
 jminjie@google.com
 satk@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
\ No newline at end of file
+xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 95a2da9..51a0c99 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -111,8 +111,7 @@
         return nullptr;
     }
     if (preferredRateNanos <= 0) {
-        ALOGE("%s: PerformanceHint invalid preferred rate.", __FUNCTION__);
-        return nullptr;
+        preferredRateNanos = -1L;
     }
     return new APerformanceHintManager(std::move(manager), preferredRateNanos);
 }
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index 5668840..0d23f05 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -1,7 +1,6 @@
 set noparent
 tgunn@google.com
 breadley@google.com
-hallliu@google.com
 rgreenwalt@google.com
 amitmahajan@google.com
 fionaxu@google.com
@@ -9,9 +8,11 @@
 jminjie@google.com
 satk@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
 xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
 
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 7f258eb..9d3ce34 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -134,6 +134,7 @@
         <receiver
             android:name=".widget.PaintChipsWidget"
             android:label="@string/s_egg_name"
+            android:exported="true"
             android:enabled="false">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -145,4 +146,4 @@
         </receiver>
     </application>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 8951e0d..dba1ab4 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -83,7 +83,7 @@
     <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"మీ భద్రత దృష్ట్యా, ఈ సోర్సు నుండి తెలియని యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మీ టాబ్లెట్ ప్రస్తుతం అనుమతించబడదు. మీరు దీన్ని సెట్టింగ్‌లలో మార్చవచ్చు."</string>
     <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"మీ భద్రత దృష్ట్యా, ఈ సోర్సు నుండి తెలియని యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మీ టీవీ ప్రస్తుతం అనుమతించబడదు. మీరు దీన్ని సెట్టింగ్‌లలో మార్చవచ్చు."</string>
     <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"మీ భద్రత దృష్ట్యా, ఈ సోర్సు నుండి తెలియని యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మీ ఫోన్ ప్రస్తుతం అనుమతించబడదు. మీరు దీన్ని సెట్టింగ్‌లలో మార్చవచ్చు."</string>
-    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"తెలియని యాప్‌లు మీ ఫోన్ పైన, వ్యక్తిగత డేటా పైన దాడి చేయడానికి ఎక్కువగా అవకాశం ఉంటుంది. ఈ యాప్ను ఇన్‌స్టాల్ చేయడం ద్వారా, దాని వినియోగంతో మీ ఫోన్‌కు ఏదైనా నష్టం జరిగితే లేదా మీ డేటాను కోల్పోతే అందుకు మీరే బాధ్యత వహిస్తారని అంగీకరిస్తున్నారు."</string>
+    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"తెలియని యాప్‌లు మీ ఫోన్ పైన, వ్యక్తిగత డేటా పైన దాడి చేయడానికి ఎక్కువగా అవకాశం ఉంటుంది. ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దాని వినియోగంతో మీ ఫోన్‌కు ఏదైనా నష్టం జరిగితే లేదా మీ డేటాను కోల్పోతే అందుకు మీరే బాధ్యత వహిస్తారని అంగీకరిస్తున్నారు."</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"మీ టాబ్లెట్ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్‌లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టాబ్లెట్‌కు ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string>
     <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"మీ టీవీ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్‌లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టీవీకి ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"కొనసాగించు"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
index bc740ab..6a9145d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/WearPackageUtil.java
@@ -66,8 +66,8 @@
     /**
      * In order to make sure that the Wearable Asset Manager has a reasonable apk that can be used
      * by the PackageManager, we will parse it before sending it to the PackageManager.
-     * Unfortunately, PackageParser needs a file to parse. So, we have to temporarily convert the fd
-     * to a File.
+     * Unfortunately, ParsingPackageUtils needs a file to parse. So, we have to temporarily convert
+     * the fd to a File.
      *
      * @param context
      * @param fd FileDescriptor to convert to File
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 266fc78..1f80a3e 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -170,7 +170,14 @@
     }
 
     /**
-     * Sets image drawable to display image in {@link LottieAnimationView}
+     * Gets the lottie illustration resource id.
+     */
+    public int getLottieAnimationResId() {
+        return mImageResId;
+    }
+
+    /**
+     * Sets the image drawable to display image in {@link LottieAnimationView}.
      *
      * @param imageDrawable the drawable of an image
      */
@@ -183,7 +190,16 @@
     }
 
     /**
-     * Sets image uri to display image in {@link LottieAnimationView}
+     * Gets the image drawable from display image in {@link LottieAnimationView}.
+     *
+     * @return the drawable of an image
+     */
+    public Drawable getImageDrawable() {
+        return mImageDrawable;
+    }
+
+    /**
+     * Sets the image uri to display image in {@link LottieAnimationView}.
      *
      * @param imageUri the Uri of an image
      */
@@ -195,6 +211,15 @@
         }
     }
 
+    /**
+     * Gets the image uri from display image in {@link LottieAnimationView}.
+     *
+     * @return the Uri of an image
+     */
+    public Uri getImageUri() {
+        return mImageUri;
+    }
+
     private void resetImageResourceCache() {
         mImageDrawable = null;
         mImageUri = null;
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-af/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-af/strings.xml
new file mode 100644
index 0000000..0a4288c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Instellings"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-am/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-am/strings.xml
new file mode 100644
index 0000000..f8db6d8
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ቅንብሮች"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ar/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ar/strings.xml
new file mode 100644
index 0000000..778715c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"الإعدادات"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-as/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-as/strings.xml
new file mode 100644
index 0000000..21be4ad
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ছেটিং"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-az/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-az/strings.xml
new file mode 100644
index 0000000..064f14a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ayarlar"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..d51823f
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Podešavanja"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-be/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-be/strings.xml
new file mode 100644
index 0000000..e6c513e
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Налады"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bg/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bg/strings.xml
new file mode 100644
index 0000000..df46ee7
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Настройки"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bn/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bn/strings.xml
new file mode 100644
index 0000000..31eb432
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"সেটিংস"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bs/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bs/strings.xml
new file mode 100644
index 0000000..442217a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Postavke"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ca/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ca/strings.xml
new file mode 100644
index 0000000..5077025
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Configuració"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-cs/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-cs/strings.xml
new file mode 100644
index 0000000..96d9019
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Nastavení"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-da/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-da/strings.xml
new file mode 100644
index 0000000..fa2b17e
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Indstillinger"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-de/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-de/strings.xml
new file mode 100644
index 0000000..bbc309c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Einstellungen"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-el/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-el/strings.xml
new file mode 100644
index 0000000..b7b7326
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ρυθμίσεις"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rAU/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..b048293
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Settings"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rCA/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..b048293
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Settings"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rGB/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..b048293
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Settings"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rIN/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..b048293
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Settings"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rXC/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..d5c868b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎Settings‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es-rUS/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..7146861
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Configuración"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es/strings.xml
new file mode 100644
index 0000000..64dddc9
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ajustes"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-et/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-et/strings.xml
new file mode 100644
index 0000000..b9c0e6f
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Seaded"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-eu/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-eu/strings.xml
new file mode 100644
index 0000000..1033ce2
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ezarpenak"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fa/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fa/strings.xml
new file mode 100644
index 0000000..76a8bd7
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"تنظیمات"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fi/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fi/strings.xml
new file mode 100644
index 0000000..6c0caaa
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Asetukset"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c894348
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Paramètres"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr/strings.xml
new file mode 100644
index 0000000..c894348
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Paramètres"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gl/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gl/strings.xml
new file mode 100644
index 0000000..7146861
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Configuración"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gu/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gu/strings.xml
new file mode 100644
index 0000000..7ae0ea2
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"સેટિંગ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hi/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hi/strings.xml
new file mode 100644
index 0000000..f38a00f
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"सेटिंग"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hr/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hr/strings.xml
new file mode 100644
index 0000000..442217a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Postavke"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hu/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hu/strings.xml
new file mode 100644
index 0000000..bdab372
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Beállítások"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hy/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hy/strings.xml
new file mode 100644
index 0000000..d91474a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Կարգավորումներ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-in/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-in/strings.xml
new file mode 100644
index 0000000..ceb5aa7
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Setelan"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-is/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-is/strings.xml
new file mode 100644
index 0000000..bd3d863
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Stillingar"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-it/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-it/strings.xml
new file mode 100644
index 0000000..1c0204d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Impostazioni"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-iw/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-iw/strings.xml
new file mode 100644
index 0000000..28ff3e72
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"הגדרות"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ja/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ja/strings.xml
new file mode 100644
index 0000000..b8acb7b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"設定"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ka/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ka/strings.xml
new file mode 100644
index 0000000..671fc1c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"პარამეტრები"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kk/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kk/strings.xml
new file mode 100644
index 0000000..bcd6784b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Параметрлер"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-km/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-km/strings.xml
new file mode 100644
index 0000000..df2c7d0
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ការកំណត់"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kn/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kn/strings.xml
new file mode 100644
index 0000000..aab8bed
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ko/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ko/strings.xml
new file mode 100644
index 0000000..8a54318
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"설정"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml
new file mode 100644
index 0000000..f4a893a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Жөндөөлөр"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lo/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lo/strings.xml
new file mode 100644
index 0000000..2a91bc3
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ການຕັ້ງຄ່າ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lt/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lt/strings.xml
new file mode 100644
index 0000000..e452cbb
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Nustatymai"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lv/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lv/strings.xml
new file mode 100644
index 0000000..e8bb102
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Iestatījumi"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mk/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mk/strings.xml
new file mode 100644
index 0000000..6031e9f
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Поставки"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ml/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ml/strings.xml
new file mode 100644
index 0000000..cb613a1
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ക്രമീകരണം"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mn/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mn/strings.xml
new file mode 100644
index 0000000..194aa02
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Тохиргоо"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mr/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mr/strings.xml
new file mode 100644
index 0000000..f2f027a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"सेटिंग्ज"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ms/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ms/strings.xml
new file mode 100644
index 0000000..51c2f19
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Tetapan"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-my/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-my/strings.xml
new file mode 100644
index 0000000..a29153b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ဆက်တင်များ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nb/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nb/strings.xml
new file mode 100644
index 0000000..fdfdecd
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Innstillinger"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ne/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ne/strings.xml
new file mode 100644
index 0000000..e1a5b1b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"सेटिङ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nl/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nl/strings.xml
new file mode 100644
index 0000000..9a7365d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Instellingen"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml
new file mode 100644
index 0000000..8b211e7
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ସେଟିଂସ୍"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pa/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pa/strings.xml
new file mode 100644
index 0000000..23b79a1
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ਸੈਟਿੰਗਾਂ"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pl/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pl/strings.xml
new file mode 100644
index 0000000..45c6e98
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ustawienia"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rBR/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..87dbe7d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Configurações"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..5ac7278
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Definições"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt/strings.xml
new file mode 100644
index 0000000..87dbe7d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Configurações"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ro/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ro/strings.xml
new file mode 100644
index 0000000..7d20417
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Setări"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ru/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ru/strings.xml
new file mode 100644
index 0000000..df46ee7
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Настройки"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-si/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-si/strings.xml
new file mode 100644
index 0000000..10f8475
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"සැකසීම්"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sk/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sk/strings.xml
new file mode 100644
index 0000000..51b5bea
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Nastavenia"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sl/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sl/strings.xml
new file mode 100644
index 0000000..41b33fe
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Nastavitve"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sq/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sq/strings.xml
new file mode 100644
index 0000000..8c0c322
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Cilësimet"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sr/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sr/strings.xml
new file mode 100644
index 0000000..1478a00
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Подешавања"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sv/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sv/strings.xml
new file mode 100644
index 0000000..ef54206
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Inställningar"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sw/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sw/strings.xml
new file mode 100644
index 0000000..d5dbf19
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Mipangilio"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ta/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ta/strings.xml
new file mode 100644
index 0000000..f929429
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"அமைப்புகள்"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-te/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-te/strings.xml
new file mode 100644
index 0000000..154c9ac
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"సెట్టింగ్‌లు"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-th/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-th/strings.xml
new file mode 100644
index 0000000..8e7218d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"การตั้งค่า"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tl/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tl/strings.xml
new file mode 100644
index 0000000..f923a18
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Mga Setting"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tr/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tr/strings.xml
new file mode 100644
index 0000000..064f14a
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Ayarlar"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uk/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uk/strings.xml
new file mode 100644
index 0000000..8f03a19
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Налаштування"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ur/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ur/strings.xml
new file mode 100644
index 0000000..24e76a6
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"ترتیبات"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uz/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uz/strings.xml
new file mode 100644
index 0000000..e8fb658
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Sozlamalar"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-vi/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-vi/strings.xml
new file mode 100644
index 0000000..ab7136b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Cài đặt"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rCN/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..9c74a49
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"设置"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rHK/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..b8acb7b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"設定"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rTW/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..b8acb7b
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"設定"</string>
+</resources>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zu/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zu/strings.xml
new file mode 100644
index 0000000..bb87ec2
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+   -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="settings_label" msgid="5948970810295631236">"Amasethingi"</string>
+</resources>
diff --git a/packages/SettingsLib/lint-baseline.xml b/packages/SettingsLib/lint-baseline.xml
index f6d6ca6..d6ea73d 100644
--- a/packages/SettingsLib/lint-baseline.xml
+++ b/packages/SettingsLib/lint-baseline.xml
@@ -892,4 +892,26 @@
             column="59"/>
     </issue>
 
+    <issue
+        id="NewApi"
+        message="Call requires API level S (current min is 29): `android.os.UserManager#isUserForeground`"
+        errorLine1="                .getSystemService(UserManager.class).isUserForeground();"
+        errorLine2="                                                     ~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java"
+            line="120"
+            column="54"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 29): `android.os.UserManager#isUserForeground`"
+        errorLine1="                .getSystemService(UserManager.class).isUserForeground();"
+        errorLine2="                                                     ~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java"
+            line="120"
+            column="54"/>
+    </issue>
+
 </issues>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 87bc1d9..99edaff 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Draadlose skermsertifisering"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktiveer Wi-Fi-woordryke aanmelding"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Regulering van Wi-Fi-opsporing"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nie-aanhoudende MAC-verewekansiging vir wi-fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data is altyd aktief"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardewareversnelling vir verbinding"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Wys opsies vir draadlose skermsertifisering"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag batteryverbruik en verbeter netwerk se werkverrigting"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wanneer hierdie modus geaktiveer is, kan hierdie toestel se MAC-adres verander elke keer wanneer dit aan \'n netwerk koppel waarvoor MAC-verewekansiging geaktiveer is."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Beperk"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Onbeperk"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Loggerbuffer se groottes"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d2e28f3..a6aa725 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"የWi‑Fi ተጨማሪ ቃላት ምዝግብ ማስታወሻ መያዝ"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"የWi-Fi ወጥ ያልሆነ ማክ የዘፈቀደ ማድረግ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"የተንቀሳቃሽ ስልክ ውሂብ ሁልጊዜ ገቢር ነው"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"የባትሪ መላሸቅን ይቀንሳል እንዲሁም የአውታረ መረብ አፈጻጸም ብቃትን ያሻሽላል"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ይህ ሁነታ ሲነቃ የዚህ መሣሪያ የማክ አድራሻ የዘፈቀደ የማክ አድራሻ ከነቃለት አውታረ መረብ ጋር በተገናኘ ጊዜ ሁሉ ሊቀየር ይችላል።"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"የሚለካ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ያልተለካ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"የምዝግብ ማስታወሻ ያዥ መጠኖች"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index ece8e14..24d9873 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"شهادة عرض شاشة لاسلكي"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏تفعيل تسجيل Wi‑Fi Verbose"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‏تقييد البحث عن شبكات Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏التوزيع العشوائي لعناوين MAC غير الثابتة لشبكة Wi‑Fi."</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"بيانات الجوّال نشطة دائمًا"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"تسريع الأجهزة للتوصيل"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‏زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"لتقليل استهلاك البطارية وتحسين أداء الشبكة"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"‏عند تفعيل هذا الوضع، قد يتم تغيير عنوان MAC لهذا الجهاز في كل مرة تتصل فيها بشبكة تم تفعيل التوزيع العشوائي لعناوين MAC عليها."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"تفرض تكلفة استخدام"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"بدون قياس"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 626a8ad..6dd95a3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ৱাই-ফাই স্কেনৰ নিয়ন্ত্ৰণ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"অবিৰত ৱাই-ফাই সংযোগ নথকা MACৰ যাদৃচ্ছিকীকৰণ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ম’বাইল ডেটা সদা-সক্ৰিয়"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"বেটাৰীৰ খৰচ কমায় আৰু নেটৱৰ্কৰ কাৰ্যক্ষমতা বৃদ্ধি কৰে"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"এই ম’ডটো সক্ষম হৈ থাকিলে, এই ডিভাইচটোৱে MAC যাদৃচ্ছিকীকৰণ সক্ষম কৰি থোৱা কোনো নেটৱৰ্কত প্ৰতিবাৰ সংযোগ হোৱাৰ সময়ত ইয়াৰ MAC ঠিকনাটো হয়তো সলনি হ’ব।"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"নিৰিখ-নিৰ্দিষ্ট"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"নিৰিখ অনিৰ্দিষ্ট"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"লগাৰৰ বাফাৰৰ আকাৰ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 3980547..0c91459 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz monitor sertifikatlaşması"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Çoxsözlü Girişə icazə verin"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi axtarışının məhdudlaşdırılması"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi müvəqqəti MAC randomizasiyası"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil data həmişə aktiv"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Modem rejimində cihaz sürətləndiricisi"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazları adsız göstərilsin"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorların sertifikasiya parametrləri göstərilsin"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Enerji sərfiyyatını azaldır və şəbəkənin işini yaxşılaşdırır"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu rejim aktiv edildikdə, bu cihaz hər dəfə MAC randomizasiyası aktiv olan şəbəkəyə qoşulanda onun MAC ünvanı dəyişə bilər."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Tarif sayğacılı"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Limitsiz"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi ölçüsü"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 6d993d8..4db3717 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikacija bežičnog ekrana"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljniju evidenciju za Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje WiFi skeniranja"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumično razvrstavanje MAC adresa po WiFi-ju sa prekidima"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci su uvek aktivni"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje privezivanja"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikazuje opcije za sertifikaciju bežičnog ekrana"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava učinak mreže"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je ovaj režim omogućen, MAC adresa ovog uređaja može da se promeni svaki put kada se poveže sa mrežom na kojoj je omogućeno nasumično razvrstavanje MAC adresa."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Sa ograničenjem"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine bafera podataka u programu za evidentiranje"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 1ef3806..604610b 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Сертыфікацыя бесправаднога экрана"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Уключыць падрабязны журнал Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Рэгуляванне пошуку сетак Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Рандамізацыя выпадковых MAC-адрасоў у сетках Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мабільная перадача даных заўсёды актыўная"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратнае паскарэнне ў рэжыме мадэма"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Паказаць опцыі сертыфікацыі бесправаднога экрана"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зніжае расход зараду акумулятара і павышае прадукцыйнасць мабільных сетак"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Калі ўключаны гэты рэжым, MAC-адрас гэтай прылады можа змяняцца падчас кожнага падключэння да сеткі з актыўнай рандамізацыяй MAC-адрасоў."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Сетка з улікам трафіка"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Сетка без уліку трафіка"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Памеры буфера журнала"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index fdf26af..39a1ff2 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Безжичен дисплей"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Активиране на „многословно“ регистр. на Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничаване на сканирането за Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Рандомизиране на временните MAC адреси за Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Винаги активни мобилни данни"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардуерно ускорение на тетъринга"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показване на опциите за сертифициране на безжичния дисплей"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Намалява изразходването на батерията и подобрява ефективността на мрежата"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Когато този режим е включен, MAC адресът на устройството може да се променя при всяко свързване с мрежа, за която е активирана функцията за рандомизиране на MAC адреса."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"С отчитане"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без отчитане"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Размери на регистрац. буфери"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 0fd9ae5..5c9a3e0 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ওয়্যারলেস ডিসপ্লে সার্টিফিকেশন"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"ওয়াই-ফাই ভারবোস লগিং চালু করুন"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ওয়াই-ফাই স্ক্যান থ্রোটলিং"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"অল্প সময় ওয়াই-ফাই নেটওয়ার্কে যুক্ত থাকে এমন MAC অ্যাড্রেসের র‍্যান্ডমাইজেশন"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ব্যাটারির খরচ কমায় এবং নেটওয়ার্কের পারফর্ম্যান্স উন্নত করে"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"এই মোডটি চালু থাকলে, MAC অ্যাড্রেসের র‍্যান্ডমাইজেশনের সুবিধা চালু আছে এমন কোনও নেটওয়ার্কে প্রত্যেকবার কানেক্ট করার সময় ডিভাইসের MAC অ্যাড্রেস পরিবর্তিত হতে পারে।"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"মিটার্ড"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"পরিমাপ করা নয়"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"লগার বাফারের আকারগুলি"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index a52f297..5b51efa 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljni zapisnik za WiFi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje skeniranja WiFi-ja"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumičan odabir MAC adrese prema WiFi mreži s prekidima"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Prijenos podataka na mobilnoj mreži uvijek aktivan"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzavanje za povezivanje putem mobitela"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećani nivo zapisnika za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava performanse mreže"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je omogućen ovaj način rada, MAC adresa ovog uređaja se može promijeniti svaki put kada se poveže na mrežu koja ima omogućen nasumični odabir MAC adresa."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"S naplatom"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mreža bez naplate"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međumemorije zapisnika"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 632ae84..948d3a0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificació de pantalla sense fil"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Activa el registre Wi‑Fi detallat"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitació de la cerca de xarxes Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorització de MAC no persistent per a connexions Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dades mòbils sempre actives"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Acceleració per maquinari per a compartició de xarxa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra les opcions per a la certificació de pantalla sense fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Augmenta el nivell de registre de la connexió Wi‑Fi i es mostra per SSID RSSI al selector de Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Redueix el consum de bateria i millora el rendiment de la xarxa"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quan aquest mode està activat, és possible que l’adreça MAC d\'aquest dispositiu canviï cada vegada que es connecti a una xarxa amb l\'aleatorització d\'adreces MAC activada."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la mem. intermèdia del registrador"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index ad1ba35..0e15848 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikace bezdrátového displeje"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné protokolování Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Přibrždění vyhledávání Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Při připojování k sítím Wi‑Fi používat proměnlivé náhodné adresy MAC"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilní data jsou vždy aktivní"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarová akcelerace tetheringu"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Snižuje vyčerpávání baterie a vylepšuje výkon sítě"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Když je tento režim aktivován, adresa MAC tohoto zařízení se může změnit pokaždé, když se zařízení připojí k síti s aktivovanou randomizací adres MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Měřená"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neměřená"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávací paměť protokolovacího nástroje"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 98020ef..4fdf435 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificering af trådløs skærm"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivér detaljeret Wi-Fi-logføring"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrænsning af Wi-Fi-scanning"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ikke-vedvarende MAC-randomisering via Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er altid aktiveret"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareacceleration ved netdeling"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis valgmuligheder for certificering af trådløs skærm"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reducerer batteriforbruget og forbedrer netværkets effektivitet"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Når denne tilstand er aktiveret, skifter enhedens MAC-adresse muligvis, hver gang den opretter forbindelse til et netværk, hvor MAC-randomisering er aktiveret."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Forbrugsafregnet"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ikke forbrugsafregnet"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Størrelser for Logger-buffer"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 4c5b04f..489c7c7 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Zertifizierung für kabellose Übertragung"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ausführliche WLAN-Protokollierung aktivieren"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Drosselung der WLAN-Suche"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nicht persistente, zufällige Generierung von MAC-Adressen für WLAN"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile Datennutzung immer aktiviert"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarebeschleunigung für Tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"WLAN-Protokollierungsebene erhöhen, in WLAN-Auswahl für jede SSID RSSI anzeigen"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen zufällig generiert werden."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ohne Datenlimit"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d28da59..8cd8387 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Πιστοποίηση ασύρματης οθόνης"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ενεργοποίηση λεπτομερ. καταγραφής Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Περιορισμός σάρωσης Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Μη σταθερή τυχαία σειρά MAC σε Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Σύνδεση επιτάχυνσης υλικού"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Περιορίζει την κατανάλωση της μπαταρίας και βελτιώνει την απόδοση του δικτύου"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Όταν ενεργοποιηθεί αυτή η λειτουργία, η διεύθυνση MAC αυτής της συσκευής μπορεί να αλλάζει κάθε φορά που συνδέεται σε ένα δίκτυο όπου έχει ενεργοποιηθεί η τυχαία σειρά διευθύνσεων MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Μέτρηση με βάση τη χρήση"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Χωρίς μέτρηση με βάση τη χρήση"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Μέγεθος προσωρινής μνήμης για τη λειτουργία καταγραφής"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 69e6387..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 252ea4e..4ad9894 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 69e6387..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 69e6387..a6f1bfc 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi non‑persistent MAC randomisation"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"When this mode is enabled, this device’s MAC address may change each time that it connects to a network that has MAC randomisation enabled."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index cb22c37..c8a7363 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎Wireless display certification‎‏‎‎‏‎"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎Enable Wi‑Fi Verbose Logging‎‏‎‎‏‎"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎Wi‑Fi scan throttling‎‏‎‎‏‎"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‎Wi‑Fi non‑persistent MAC randomization‎‏‎‎‏‎"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎Mobile data always active‎‏‎‎‏‎"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎Tethering hardware acceleration‎‏‎‎‏‎"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎Show Bluetooth devices without names‎‏‎‎‏‎"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎Show options for wireless display certification‎‏‎‎‏‎"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker‎‏‎‎‏‎"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎Reduces battery drain &amp; improves network performance‎‏‎‎‏‎"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎When this mode is enabled, this device’s MAC address may change each time it connects to a network that has MAC randomization enabled.‎‏‎‎‏‎"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‎‎Metered‎‏‎‎‏‎"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎Unmetered‎‏‎‎‏‎"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎Logger buffer sizes‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index d744e7f..27fbf44 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro detallado de Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación de búsqueda de Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorización de MAC no persistente para conexiones Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activados"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware de conexión mediante dispositivo móvil"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"De uso medido"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 558583f..f33a29d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro de Wi-Fi detallado"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar búsqueda de redes Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Aleatorización de MAC no persistente en conexiones Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activos"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración por hardware para conexión compartida"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Muestra opciones para la certificación de la pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta el nivel de registro de la conexión Wi-Fi y se muestra por SSID RSSI en el selector Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de las redes"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Medida"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"No medida"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños del búfer para registrar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 9046916..0ede248 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Juhtmeta ekraaniühenduse sertifitseerimine"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Luba WiFi sõnaline logimine"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"WiFi-skannimise ahendamine"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"WiFi-võrgu mittepüsiva MAC-aadressi juhuslikustamine"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Hoia mobiilne andmeside alati aktiivne"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Ühenduse jagamise riistvaraline kiirendus"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Aeglustab aku tühjenemist ja parandab võrgu toimivust"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kui see režiim on lubatud, võidakse selle seadme MAC-aadressi muuta iga kord, kui see ühendatakse võrguga, milles on juhuslikustatud MAC-aadressi määramine lubatud."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Mahupõhine"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mittemahupõhine"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logija puhvri suurused"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 313d9edd..1f8d616 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Hari gabe bistaratzeko ziurtagiria"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Gaitu wifi-sareetan saioa hasteko modu xehatua"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-sareen bilaketaren muga"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wifi-konexioetan iraunkorrak ez diren MAC helbideak ausaz antolatzea"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Datu-konexioa beti aktibo"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Modu hau gaituta dagoenean, baliteke gailuaren MAC helbidea aldatzea MAC helbideak ausaz antolatzeko aukera gaituta daukan sare batera konektatzen den bakoitzean."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Sare neurtua"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neurtu gabeko sarea"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Erregistroen buffer-tamainak"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f5f18a3..b53a83d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"گواهینامه نمایش بی‌سیم"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏فعال کردن گزارش‌گیری طولانی Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‏محدود کردن اسکن کردن Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏تصادفی‌سازی MAC غیرپایای Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"داده تلفن همراه همیشه فعال باشد"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"شتاب سخت‌افزاری اشتراک‌گذاری اینترنت"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاه‌های بلوتوث بدون نام"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"نمایش گزینه‌ها برای گواهینامه نمایش بی‌سیم"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‏افزایش سطح گزارش‌گیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخاب‌کننده Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"تخلیه باتری راکاهش می‌دهد و عملکرد شبکه را بهبود می‌بخشد"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"‏اگر این حالت فعال باشد، هر بار این دستگاه به شبکه‌ای متصل شود که تصادفی‌سازی MAC در آن فعال است، ممکن است نشانی MAC آن تغییر کند."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"محدودشده"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"محدودنشده"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"اندازه‌های حافظه موقت ثبت‌کننده"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index fff3c55..e116a19 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Langattoman näytön sertifiointi"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Käytä Wi-Fin laajennettua lokikirjausta"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-haun rajoitus"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"MAC-satunnaistaminen, jos Wi-Fi ei ole kiinteä"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiilidata aina käytössä"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Laitteistokiihdytyksen yhteyden jakaminen"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Vähentää virrankulutusta ja parantaa verkon toimintaa"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kun tämä tila on päällä, laitteen MAC-osoite voi muuttua aina, kun laite yhdistää verkkoon, jossa MAC-satunnaistaminen on käytössä"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Maksullinen"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Maksuton"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Lokipuskurien koot"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6205cfd..2291c6f 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certification de l\'affichage sans fil"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser enreg. données Wi-Fi détaillées"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche de réseaux Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Réorganisation aléatoire MAC non persistante du Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Données cellulaires 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>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecte à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index bb41975e..a225b74 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -252,8 +252,7 @@
     <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>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Sélection aléatoire de l\'adresse MAC non persistante 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>
@@ -285,8 +284,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>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quand ce mode est activé, l\'adresse MAC de cet appareil peut changer chaque fois qu\'il se connecte à un réseau où 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 f96b187..bbf8e74 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificado de visualización sen fíos"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Activar rexistro detallado da wifi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación da busca de wifi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Orde aleatoria de enderezos MAC non persistentes para conexións wifi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móbiles sempre activados"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware para conexión compartida"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opcións para o certificado de visualización sen fíos"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta o nivel de rexistro da wifi, móstrao por SSID RSSI no selector de wifi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce o consumo de batería e mellora o rendemento da rede"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Cando este modo está activado, o enderezo MAC pode cambiar cada vez que se este dispositivo se conecta a unha rede que teña activada a orde aleatoria de enderezos MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Rede sen tarifa plana"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Rede con tarifa plana"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaño dos búfers do rexistrador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9fc70cf..eedadc9 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"વાયરલેસ ડિસ્પ્લે પ્રમાણન"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"વાઇ-ફાઇ વર્બોઝ લૉગિંગ ચાલુ કરો"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"વાઇ-ફાઇ સ્કૅનની ક્ષમતા મર્યાદિત કરવી"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"વાઇ-ફાઇ માટે સતત બદલાતું MAC રેન્ડમાઇઝેશન"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"મોબાઇલ ડેટા હંમેશાં સક્રિય"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ડિવાઇસ બતાવો"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"બૅટરીનો ચાર્જ ઝડપથી ઓછો થવાનું ટાળે છે અને નેટવર્કના કાર્યપ્રદર્શનમાં સુધારો કરે છે"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"આ મોડ ચાલુ કરેલો હોય ત્યારે MAC રેન્ડમાઇઝેશન ચાલુ કરેલું હોય તેવા નેટવર્ક સાથે આ ડિવાઇસ કનેક્ટ થશે, ત્યારે દર વખતે તેનું MAC ઍડ્રેસ બદલાય તેવું બની શકે છે."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"મીટર કરેલું"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"મીટર ન કરેલ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"લોગર બફર કદ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 40ce2e6..c065f9a 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिसप्ले सर्टिफ़िकेशन"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"वाई-फ़ाई वर्बोस लॉगिंग चालू करें"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"वाई-फ़ाई के लिए स्कैन की संख्या कम करें"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"थोड़े समय के लिए वाई-फ़ाई नेटवर्क से जुड़ने पर MAC पता बदलने की सुविधा"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा हमेशा चालू"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिसप्ले सर्टिफ़िकेशन के विकल्प दिखाएं"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाई-फ़ाई लॉगिंग का स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बैटरी की खपत कम और नेटवर्क की परफ़ॉर्मेंस बेहतर होती है"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"जब यह मोड चालू होता है, तब नेटवर्क से कनेक्ट होने पर हर बार इस डिवाइस का MAC पता बदल सकता है. ऐसा तब होता है, जब डिवाइस किसी ऐसे नेटवर्क से जुड़ता है जिस पर MAC पता बदलने की सुविधा चालू होती है."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"डेटा इस्तेमाल करने की सीमा तय की गई है"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"डेटा इस्तेमाल करने की सीमा तय नहीं की गई है"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफ़र आकार"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 5582ca9..0727c83 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući opširnu prijavu na Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje traženja Wi-Fija"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nasumični odabir nepostojane MAC adrese za Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci uvijek aktivni"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje za modemsko povezivanje"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava rad mreže"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kada je omogućen ovaj način, MAC adresa ovog uređaja može se promijeniti svaki put kad se uređaj poveže s mrežom na kojoj je omogućen nasumični odabir MAC-a."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"S ograničenim prometom"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja prometa"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međuspremnika zapisnika"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 95a905b..12a81a6 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Vezeték nélküli kijelző tanúsítványa"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Részletes Wi-Fi-naplózás engedélyezése"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi-hálózat szabályozása"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi nem állandó MAC-randomizációja"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"A mobilhálózati kapcsolat mindig aktív"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Internetmegosztás hardveres gyorsítása"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Csökkenti az akkumulátorhasználatot, és javítja a hálózat teljesítményét"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ha ez a mód be van kapcsolva, akkor ennek az eszköznek a MAC-címe minden alkalommal módosulhat, amikor olyan hálózathoz csatlakozik, amelyen engedélyezve van a MAC-címek randomizálása."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Forgalomkorlátos"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Nem forgalomkorlátos"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Naplózási puffer mérete"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b99cd40..1fd6c5f 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Անլար էկրանների հավաստագրում"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Միացնել Wi‑Fi մանրամասն գրանցամատյանները"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-ի որոնման սահմանափակում"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Պատահական հերթականությամբ դասավորված MAC հասցեներ Wi‑Fi ցանցում"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Բջջային ինտերնետը միշտ ակտիվ է"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Սարքակազմի արագացման միացում"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ցույց տալ անլար էկրանների հավաստագրման ընտրանքները"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Նվազեցնում է մարտկոցի սպառումը և լավացնում ցանցի աշխատանքը"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Երբ այս ռեժիմը միացված է, MAC հասցեն կարող է փոխվել ամեն անգամ, երբ սարքը միանա որևէ ցանցի, որում միացված է MAC հասցեների պատահական ընտրությունը։"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Վճարովի թրաֆիկ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Անսահմանափակ թրաֆիկ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Մատյանի բուֆերի չափերը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index b293fe8..3480411 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikasi layar nirkabel"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktifkan Pencatatan Log Panjang Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pembatasan pemindaian Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Pengacakan tidak tetap MAC Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Data seluler selalu aktif"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Akselerasi hardware tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Memperlambat kehabisan baterai &amp; meningkatkan performa jaringan"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Jika mode ini diaktifkan, alamat MAC perangkat ini dapat berubah setiap kali terhubung ke jaringan yang mengaktifkan pengacakan MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Berbayar"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak berbayar"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Ukuran buffer pencatat log"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 1e338f8..8b56f6a 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Vottun þráðlausra skjáa"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Kveikja á ítarlegri skráningu Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Hægja á Wi‑Fi leit"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Slembiröðun tímabundinna MAC-vistfanga um Wi-Fi tengingu"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Alltaf kveikt á farsímagögnum"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Vélbúnaðarhröðun fyrir tjóðrun"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Dregur úr rafhlöðunotkun og eykur netafköst"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Þegar kveikt er á þessari stillingu gæti MAC-vistfang þessa tækis breyst í hvert sinn sem það tengist neti sem er með kveikt á slembivali MAC-vistfanga."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Mæld notkun"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Notkun ekki mæld"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Annálsritastærðir biðminna"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 3ac90cf..def0909 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificazione display wireless"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Attiva logging dettagliato Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limita ricerca di reti Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizzazione non persistente dell\'indirizzo MAC Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dati mobili sempre attivi"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering accelerazione hardware"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opzioni per la certificazione display wireless"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta livello di logging Wi-Fi, mostra SSID RSSI nel selettore Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Riduce il consumo della batteria e migliora le prestazioni della rete"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando questa modalità è attiva, l\'indirizzo MAC del dispositivo potrebbe cambiare ogni volta che il dispositivo si connette a una rete con randomizzazione degli indirizzi MAC attiva."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"A consumo"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non a consumo"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Dimensioni buffer logger"</string>
@@ -446,7 +444,7 @@
     <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration" msgid="318215464914990578">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+    <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Il telefono potrebbe spegnersi a breve"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Il tablet potrebbe spegnersi a breve"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Il dispositivo potrebbe spegnersi a breve"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 3961f9d..67247ea 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"‏אישור של תצוגת Wi-Fi"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏הפעלת רישום מפורט של Wi‑Fi ביומן"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‏ויסות סריקה לנקודות Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏רנדומיזציה של כתובות MAC משתנות ברשתות Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"חבילת הגלישה פעילה תמיד"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‏הצגת מכשירי Bluetooth ללא שמות"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"‏הצגת אפשרויות עבור אישור של תצוגת Wi-Fi"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‏העלאת רמת הרישום של Wi‑Fi ביומן, הצגה לכל SSID RSSI ב-Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"אפשרות זו מפחיתה את קצב התרוקנות הסוללה ומשפרת את ביצועי הרשת"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"‏כשהמצב הזה מופעל, כתובת ה-MAC של המכשיר הזה יכולה להשתנות בכל פעם שהוא מתחבר לרשת שבה פועלת רנדומיזציה של כתובות MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"חיוב לפי שימוש בנתונים"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"לא נמדדת"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"גודלי מאגר של יומן רישום"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1847c56..1a7d9ba 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ワイヤレス ディスプレイ認証"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi 詳細ログの有効化"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi スキャン スロットリング"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi-Fi 非永続的 MAC ランダム化"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"モバイルデータを常に ON にする"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"テザリング時のハードウェア アクセラレーション"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ワイヤレス ディスプレイ認証のオプションを表示"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ログレベルを上げて、Wi-Fi 選択ツールで SSID RSSI ごとに表示します"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"電池の消耗が軽減され、ネットワーク パフォーマンスが改善されます"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ON にすると、MAC アドレスのランダム化が有効なネットワークに接続するたびに、このデバイスの MAC アドレスが変わる可能性があります。"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"従量制"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"定額制"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ログバッファのサイズ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index db94c72..33d3e65 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"უსადენო ეკრანის სერტიფიცირება"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi-ს დაწვრილებითი აღრიცხვის ჩართვა"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi სკანირების რეგულირება"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi-ის MAC მისამართების არამუდმივი რანდომიზაცია"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"მობილური ინტერნეტის ყოველთვის გააქტიურება"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ტეტერინგის აპარატურული აჩქარება"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ამცირებს ბატარეის ხარჯვას და აუმჯობესებს ქსელის მუშაობას"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"როდესაც ეს რეჟიმი ჩართულია, ამ მოწყობილობის MAC მისამართი შეიძლება შეიცვალოს ისეთ ქსელთან ყოველ დაკავშირებაზე, რომელსაც ჩართული აქვს MAC მისამართის რანდომიზაცია."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"ლიმიტირებული"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"არალიმიტირებული"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ჟურნალიზაციის ბუფერის ზომები"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 4e663fc..62dff735 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Сымсыз дисплей сертификаты"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Толық мәліметті Wi‑Fi журналы"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi желілерін іздеуді шектеу"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi желісінің тұрақсыз MAC рандомизациясы"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобильдік интернет әрқашан қосулы"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Тетеринг режимінде аппаратпен жеделдету"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Сымсыз дисплей сертификаты опцияларын көрсету"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi тіркеу деңгейін арттыру, Wi‑Fi таңдағанда әр SSID RSSI бойынша көрсету"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарея зарядының шығынын азайтады және желі жұмысын жақсартады."</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Бұл режим қосулы болса, құрылғының MAC мекенжайы MAC рандомизациясы қосулы желіге жалғанған сайын өзгеруі мүмкін."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Трафик саналатын желі"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Трафик саналмайды"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферінің өлшемдері"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 2d8273e..0b23e68 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"សេចក្តីបញ្ជាក់ការបង្ហាញ​ឥត​ខ្សែ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"បើក​កំណត់ហេតុ​រៀបរាប់​ Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ការពន្យឺតការស្កេន Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ការតម្រៀប MAC ដែលមិនមានលក្ខណៈជាប់លាប់តាមលំដាប់​ចៃដន្យនៃ Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ទិន្នន័យទូរសព្ទចល័តដំណើរការជានិច្ច"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ការ​ពន្លឿនល្បឿនភ្ជាប់ដោយប្រើហាតវែរ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញ​ឧបករណ៍​ប្ល៊ូធូស​គ្មានឈ្មោះ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"បង្ហាញ​ជម្រើស​សម្រាប់​សេចក្តីបញ្ជាក់ការបង្ហាញ​ឥត​ខ្សែ"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"បង្កើនកម្រិតកំណត់ហេតុ Wi-Fi បង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសរើស Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"កាត់បន្ថយ​ការប្រើប្រាស់ថ្ម និងកែលម្អប្រតិបត្តិការ​បណ្ដាញ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"នៅពេលបើក​មុខងារនេះ អាសយដ្ឋាន MAC របស់ឧបករណ៍នេះ​អាចផ្លាស់ប្ដូរ​ រាល់ពេល​ដែលវា​ភ្ជាប់ជាមួយ​បណ្ដាញ​ដែលបានបើក​ការប្រើ MAC ចៃដន្យ។"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"មានការកំណត់"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"មិនមានការកំណត់"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ទំហំឡុកជើបាហ្វើ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 99fd1d3..3af8728 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ವೈರ್‌ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi ವೆರ್ಬೋಸ್ ಲಾಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ವೈ-ಫೈ ಸ್ಕ್ಯಾನ್ ನಿರ್ಬಂಧಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ವೈ-ಫೈ ನಿರಂತರವಲ್ಲದ MAC ಯಾದೃಚ್ಛಿಕರಣ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ಮೊಬೈಲ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ಟೆಥರಿಂಗ್‍‍ಗಾಗಿ ಹಾರ್ಡ್‍ವೇರ್ ವೇಗವರ್ಧನೆ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ವೈರ್‌ಲೆಸ್‌‌‌ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ಬ್ಯಾಟರಿ ಹೆಚ್ಚು ಬಾಳಿಕೆ ಬರುವಂತೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ನೆಟ್‌ವರ್ಕ್‌ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸುತ್ತದೆ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ಈ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, MAC ಯಾದೃಚ್ಛಿಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿದಾಗ ಈ ಸಾಧನದ MAC ವಿಳಾಸವು ಪ್ರತಿ ಬಾರಿಯೂ ಬದಲಾಗಬಹುದು."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"ಮೀಟರ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ಮೀಟರ್ ಮಾಡಲಾಗಿಲ್ಲ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ಲಾಗರ್ ಬಫರ್ ಗಾತ್ರಗಳು"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 1dd6df9..421c60f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"무선 디스플레이 인증서"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi 상세 로깅 사용"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 검색 제한"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 비지속적인 MAC 주소 무작위 순서 지정"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"항상 모바일 데이터 활성화"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"테더링 하드웨어 가속"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"무선 디스플레이 인증서 옵션 표시"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"배터리 소모를 줄이고 네트워크 성능 개선"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"이 모드를 사용 설정하면 기기가 MAC 주소 무작위 지정이 설정된 네트워크에 연결될 때마다 기기의 MAC 주소가 변경될 수 있습니다."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"종량제 네트워크"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"무제한 네트워크"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"로거 버퍼 크기"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index c1f9c23..bdc4939 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Зымсыз мониторлорду тастыктамалоо"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi таржымалы"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi тармактарын издөөнү жөнгө салуу"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi туташуусу туруксуз MAC даректерин башаламан иретте түзүү"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилдик Интернет иштей берет"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем режиминде аппараттын иштешин тездетүү"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрүнсүн"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Зымсыз мониторлорду тастыктамалоо параметрлери көрүнүп турат"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi тандалганда ар бир SSID үчүн RSSI көрүнүп турат"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батареяны үнөмдөп, тармактын иштешин жакшыртат"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Бул режим өчүрүлгөндөн кийин, түзмөк MAC дарегин башаламан иретте түзүү функциясы иштетилген тармакка туташкан сайын анын MAC дареги өзгөрүшү мүмкүн."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Трафик ченелет"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Чектелбеген тармак"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферинин өлчөмү"</string>
@@ -311,7 +309,7 @@
     <string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Орнотулуучу колдонмону текшерүү"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ADB/ADT аркылуу орнотулган колдонмолордун коопсуздугу текшерилет."</string>
-    <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрсөтүлөт"</string>
+    <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрүнөт"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Алыскы түзмөктөр өтө катуу добуш чыгарып же көзөмөлдөнбөй жатса Bluetooth \"Үндүн абсолюттук деңгээли\" функциясын өчүрөт."</string>
     <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Bluetooth Gabeldorsche функциясынын топтомун иштетет."</string>
     <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Жакшыртылган туташуу функциясын иштетет."</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 460397a..91e5c00 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ສະແດງການຮັບຮອງຂອງລະບົບໄຮ້ສາຍ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"​ເປີດ​ນຳ​ໃຊ້ການ​ເກັບ​ປະ​ຫວັດ​ Verbose Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ການຈຳກັດການສະແກນ Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ການສຸ່ມ MAC ທີ່ມີ Wi-Fi ແບບບໍ່ຖາວອນ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືຕະຫຼອດເວລາ"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ເພີ່ມ​ລະ​ດັບ​ການ​ເກັບ​ປະ​ຫວັດ Wi‑Fi, ສະ​ແດງ​ຕໍ່ SSID RSSI ​ໃນ​ Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ຫຼຸດການໃຊ້ແບັດເຕີຣີ ແລະ ປັບປຸງປະສິດທິພາບເຄືອຂ່າຍ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ຫາກເປີດການນຳໃຊ້ໂໝດນີ້, ທີ່ຢູ່ MAC ຂອງອຸປະກອນນີ້ອາດມີການປ່ຽນແປງໃນແຕ່ລະເທື່ອທີ່ມັນເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍໃດໜຶ່ງທີ່ເປີດການນຳໃຊ້ການສຸ່ມ MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"ມີການວັດແທກ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ບໍ່ໄດ້ວັດແທກ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ຂະໜາດບັບເຟີຕົວບັນທຶກ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 268b998..9887a93 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Belaidžio rodymo sertifikavimas"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Įgal. „Wi‑Fi“ daugiaž. įraš. į žurnalą"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"„Wi‑Fi“ nuskaitymo ribojimas"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"MAC atsitiktinis parinkimas esant nepastoviam „Wi‑Fi“"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiliojo ryšio duomenys visada suaktyvinti"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sumažinamas akumuliatoriaus eikvojimas ir patobulinamas tinklo našumas"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kai įgalintas šis režimas, šio įrenginio MAC adresas gali keistis kas kartą prisijungus prie tinklo, kuriame įgalintas atsitiktinis MAC parinkimas."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Matuojamas"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neišmatuotas"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Registruotuvo buferio dydžiai"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index af37618..81a566c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Bezvadu attēlošanas sertifikācija"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Iespējot Wi‑Fi detalizēto reģistrēšanu"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi meklēšanas ierobežošana"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nepastāvīgu MAC adrešu nejauša izveide Wi-Fi savienojumiem"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Vienmēr aktīvs mobilo datu savienojums"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Paātrināta aparatūras darbība piesaistei"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Samazina akumulatora izlādi un uzlabo tīkla veiktspēju"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ja šis režīms ir iespējots, šīs ierīces MAC adrese var mainīties ikreiz, kad ierīcē tiek izveidots savienojums ar tīklu, kurā ir iespējota MAC adrešu nejauša izveide."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Maksas"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bezmaksas"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Reģistrētāja buferu lielumi"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 5313511..ed64960 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Приказ на сертификација на безжична мрежа"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Овозможи преопширно пријавување Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Регулирање на скенирањето за Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Непостојана MAC-рандомизација на Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилниот интернет е секогаш активен"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско забрзување за врзување"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Покажи ги опциите за безжичен приказ на сертификат"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Го намалува искористувањето на батеријата и ја подобрува изведбата на мрежата"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Кога е овозможен режимов, MAC-адресата на уредов може да се промени секој пат кога ќе се поврзе со мрежа што има овозможена MAC-рандомизација."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Со ограничен интернет"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничен интернет"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Величини на меѓумеморија за дневникот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index f56386f..660f4b6 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"വയർലെസ് ഡിസ്‌പ്ലേ സർട്ടിഫിക്കേഷൻ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"വൈഫൈ വെർബോസ് ലോഗിംഗ് പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"വൈഫൈ സ്‌കാൻ ത്രോട്ടിലിംഗ്"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"വൈഫൈ വഴിയുള്ള, സ്ഥിരതയില്ലാത്ത MAC ക്രമരഹിതമാക്കൽ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"മൊബൈൽ ഡാറ്റ എല്ലായ്‌പ്പോഴും സജീവം"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ടെതറിംഗ് ഹാർഡ്‌വെയർ ത്വരിതപ്പെടുത്തൽ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"വയർലെസ് ഡിസ്‌പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്‌ഷനുകൾ ദൃശ്യമാക്കുക"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ബാറ്ററി ചാർജ് വേഗത്തിൽ തീരുന്ന അവസ്ഥ കുറച്ച് നെറ്റ്‌വർക്ക് പ്രകടനം മെച്ചപ്പെടുത്തുന്നു"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ഈ മോഡ് പ്രവർത്തനക്ഷമമാക്കുമ്പോൾ, MAC ക്രമരഹിതമാക്കൽ പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്ന നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുമ്പോഴെല്ലാം ഈ ഉപകരണത്തിന്റെ MAC വിലാസം മാറിയേക്കാം."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർ ചെയ്തത്"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"മീറ്റർമാപകമല്ലാത്തത്"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ലോഗർ ബഫർ വലുപ്പം"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 2c588f6..074b864 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Утасгүй дэлгэцийн сертификат"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi дэлгэрэнгүй лог-г идэвхжүүлэх"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi скан бууруулалт"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi-н байнгын бус MAC-г санамсаргүй байдлаар эмхлэх"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобайл дата байнга идэвхтэй"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем болгох техник хангамжийн хурдасгуур"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi логийн түвшнийг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарей зарцуулалтыг бууруулж, сүлжээний гүйцэтгэлийг сайжруулдаг"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Энэ горимыг идэвхжүүлсэн үед энэ төхөөрөмжийг MAC-н санамсаргүй байдлаар эмхлэх явцыг идэвхжүүлсэн сүлжээнд холбогдох бүрд үүний MAC хаягийг өөрчилж болзошгүй."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Хязгаартай"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Хязгааргүй"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Логгерын буферын хэмжээ"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 0b0a4a6..95e6f63 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रमाणीकरण"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"वाय-फाय व्हर्बोझ लॉगिंग सुरू करा"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"वाय-फाय स्कॅन थ्रॉटलिंग"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"वाय-फायचे सातत्याने न होणारे MAC रँडमायझेशन"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा नेहमी सक्रिय"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिंग हार्डवेअर अ‍ॅक्सिलरेशन"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्‍लूटूथ डिव्‍हाइस दाखवा"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाय-फाय लॉगिंग स्‍तर वाढवा, वाय-फाय सिलेक्टरमध्‍ये प्रति SSID RSSI दर्शवा"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बॅटरी जलदरीतीने संपण्यापासून रोखते आणि नेटवर्क परफॉर्मन्समध्ये सुधारणा करते"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"हा मोड सुरू केलेला असले तेव्हा, हे डिव्हाइस MAC रँडमायझेशन सुरू केलेल्या नेटवर्कशी कनेक्ट होताना प्रत्येक वेळी त्याचा MAC अ‍ॅड्रेस बदलू शकतो."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"मीटरने मोजलेले"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"मीटरने न मोजलेले"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफर आकार"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ee312fb..4390896 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Pensijilan paparan wayarles"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Dayakan Pengelogan Berjela-jela Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pendikitan pengimbasan Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Perawakan MAC tidak berterusan Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Data mudah alih sentiasa aktif"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Pecutan perkakasan penambatan"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Mengurangkan penyusutan bateri &amp; meningkatkan prestasi rangkaian"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Apabila mod ini didayakan, alamat MAC peranti ini mungkin berubah pada setiap kali peranti menyambung kepada rangkaian yang telah mendayakan perawakan MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Bermeter"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak bermeter"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Saiz penimbal pengelog"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 01cadbd..199d15c 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ကြိုးမဲ့ပြသမှု အသိအမှတ်ပြုလက်မှတ်"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Verbose မှတ်တမ်းတင်ခြင်းအား ဖွင့်မည်"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ရှာဖွေခြင်း ထိန်းချုပ်မှု"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi ပြောင်းလဲသော MAC ကျပန်းပြုလုပ်ခြင်း"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"မိုဘိုင်းဒေတာကို အမြဲဖွင့်ထားရန်"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ဘက်ထရီ အသုံးပြုမှုကို လျှော့ကျစေပြီး ကွန်ရက်စွမ်းဆောင်ရည်ကို ပိုမိုကောင်းမွန်စေသည်"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ဤမုဒ်ကို ဖွင့်ထားသည့်အခါ MAC ကျပန်းပြုလုပ်ထားသည့် ကွန်ရက်သို့ ချိတ်ဆက်လိုက်သည့်အခါတိုင်း ဤစက်၏ MAC လိပ်စာ ပြောင်းသွားနိုင်သည်။"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"အခမဲ့ မဟုတ်ပါ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"အခမဲ့"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"မှတ်တမ်းကြားခံနယ် အရွယ်အစားများ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 6fbfb49..722f98f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Trådløs skjerm-sertifisering"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Slå på detaljert Wi-Fi-loggføring"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrensning av Wi‑Fi-skanning"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ikke-vedvarende tilfeldiggjøring av MAC-adresse for Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er alltid aktiv"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvareakselerasjon for internettdeling"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis alternativer for sertifisering av trådløs skjerm"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk nivået av Wi-Fi-logging – vis per SSID RSSI i Wi-Fi-velgeren"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduserer batteriforbruket og forbedrer nettverksytelsen"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Når denne modusen er slått på, kan MAC-adressen til denne enheten endres hver gang den kobler seg til et nettverk som har tilfeldiggjøring av MAC-adresse slått på."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Med datamåling"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Uten datamåling"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Bufferstørrelser for logg"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 52282e0..a109c58 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रयोग गर्ने वा नगर्ने"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi भर्बोज लग अन गरियोस्"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi स्क्यान थ्रोटलिङ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi-Fi नन-पर्सिस्टेन्ट MAC र्‍यान्डमाइजेसन"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा सधैँ अन होस्"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ डिभाइस देखाइयोस्"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्लेसम्बन्धी विकल्प देखाइयोस्"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi लगिङ लेभल बढाइयोस्, Wi-Fi पि‍करमा प्रति SSID RSSI देखाइयोस्"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"यसले ब्याट्रीको खपत कम गर्छ र नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"यो मोड अन गरिएका बेला यो डिभाइस MAC एड्रेस बदल्ने सुविधा अन गरिएको नेटवर्कमा जति पटक कनेक्ट हुन्छ त्यति नै पटक यस डिभाइसको MAC एड्रेस पनि परिवर्तन हुन सक्छ।"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"मिटर नगरिएको"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"लगर बफरका आकारहरू"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 1ce2af9..12a47bc 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Uitgebreide wifi-logregistr. aanzetten"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-scannen beperken"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Niet-persistente MAC-herschikking in willekeurige volgorde voor wifi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data altijd actief"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareversnelling voor tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder naam tonen"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Toon opties voor certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog het logniveau voor wifi, toon per SSID RSSI in wifi-kiezer"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag het batterijverbruik en verbeter de netwerkprestaties"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Als dit aanstaat, kan het MAC-adres van dit apparaat veranderen telkens als het apparaat verbinding maakt met een netwerk waarvoor MAC-herschikking aanstaat."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Met datalimiet"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Gratis"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Logger-buffergrootten"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8ec0959..d047b17 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ୱାୟରଲେସ୍‌ ଡିସ୍‌ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"ୱାଇ-ଫାଇ ଭର୍ବୋସ୍‌ ଲଗିଙ୍ଗ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ୱାଇ-ଫାଇ ସ୍କାନ୍ ନିୟନ୍ତ୍ରଣ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ୱାଇ-ଫାଇ ଅଣ-ଅବିରତ MAC ରେଣ୍ଡମାଇଜେସନ୍"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ମୋବାଇଲ୍‌ ଡାଟା ସର୍ବଦା ସକ୍ରିୟ"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର ଆକ୍ସିଲିରେସନ୍"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍‍‌ ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ୱେୟାରଲେସ୍‌ ଡିସ୍‌ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍‌ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍‌ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ଯେତେବେଳେ ଏହି ମୋଡ୍ ସକ୍ଷମ କରାଯାଏ, ପ୍ରତ୍ୟେକ ଥର MAC ରେଣ୍ଡୋମାଇଜେସନ୍ ସକ୍ଷମ ଥିବା କୌଣସି ନେଟୱାର୍କ ସହ ଏହି ଡିଭାଇସ୍ ସଂଯୋଗ ହେଲେ ଏହାର MAC ଠିକଣା ବଦଳିପାରେ।"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"ମପାଯାଉଥିବା"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ମପାଯାଉନଥିବା"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ଲଗର୍‌ ବଫର୍‌ ସାଇଜ୍"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 0a6b5df..a310dae 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"ਵਾਈ-ਫਾਈ ਵਰਬੋਸ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"ਵਾਈ‑ਫਾਈ ਸਕੈਨ ਥਰੌਟਲਿੰਗ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"ਵਾਈ-ਫਾਈ ਲਈ ਗੈਰ-ਸਥਾਈ MAC ਬੇਤਰਤੀਬਵਾਰ"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ ਚੋਣਕਾਰ ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਘਟਾ ਕੇ ਨੈੱਟਵਰਕ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਂਦਾ ਹੈ"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ਜਦੋਂ ਇਹ ਮੋਡ ਚਾਲੂ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਇਸ ਡੀਵਾਈਸ ਦਾ MAC ਪਤਾ ਹਰ ਵਾਰ ਬਦਲ ਸਕਦਾ ਹੈ ਜਦੋਂ ਇਹ ਕਿਸੇ ਅਜਿਹੇ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੁੰਦਾ ਹੈ ਜਿਸ ਵਿੱਚ MAC ਬੇਤਰਤੀਬਵਾਰ ਚਾਲੂ ਹੁੰਦਾ ਹੈ।"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ਗੈਰ-ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ਲੌਗਰ ਬਫ਼ਰ ਆਕਾਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index ac5a7b5..011c895 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certyfikacja wyświetlacza bezprzewodowego"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Szczegółowy dziennik Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ograniczanie skanowania Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Nietrwała randomizacja adresów MAC w sieci Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilna transmisja danych zawsze aktywna"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Akceleracja sprzętowa tetheringu"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokazuj urządzenia Bluetooth bez nazw"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokazuj opcje certyfikacji wyświetlacza bezprzewodowego"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmniejsza zużycie baterii i zwiększa wydajność sieci"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kiedy ten tryb jest włączony, to adres MAC tego urządzenia może zmieniać się za każdym razem, kiedy urządzenie połączy się z siecią, która ma włączoną opcję randomizacji MAC"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Użycie danych jest mierzone"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Użycie danych nie jest mierzone"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Rozmiary bufora rejestratora"</string>
@@ -445,8 +443,8 @@
     <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Bateria może się wyczerpać do <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration" msgid="318215464914990578">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+    <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Wkrótce telefon może się wyłączyć"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Tablet może się wkrótce wyłączyć"</string>
     <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Urządzenie może się wkrótce wyłączyć"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 1bfb0b5..6804c58 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 0435ab8..30dceaf0 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de display sem fios"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar o registo verboso de Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Controlo da procura de Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Seleção aleatória do MAC não persistente Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções da certificação de display sem fios"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo rápido da bateria e melhora o desempenho da rede"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando este modo estiver ativado, o endereço MAC deste dispositivo pode mudar sempre que o mesmo estabelece ligação a uma rede que tenha a seleção aleatória do MAC ativada."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Acesso limitado"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Acesso ilimitado"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos da memória intermédia do registo"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 1bfb0b5..6804c58 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ordem aleatória de MAC não persistente no Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Quando esse modo estiver ativado, o endereço MAC do dispositivo poderá mudar toda vez que ele se conectar a uma rede com ordem aleatória de MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 63b1843..0cd7926 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certificare Ecran wireless"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Înregistrare prin Wi-Fi de volume mari de date"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitare căutare de rețele Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizarea adresei MAC nepersistente pentru Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Date mobile permanent active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accelerare hardware pentru tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce descărcarea bateriei și îmbunătățește performanța rețelei"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Când acest mod este activat, adresa MAC a dispozitivului se poate schimba de fiecare dată când se conectează la o rețea care are activată randomizarea MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Contorizată"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Necontorizată"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Dimensiunile memoriei temporare a jurnalului"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9906fc5..418af9a 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Серт. беспроводн. мониторов"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Подробный журнал Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничивать поиск сетей Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Случайные MAC-адреса в сети Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Не отключать мобильный Интернет"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Аппаратное ускорение в режиме модема"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показывать параметры сертификации беспроводных мониторов"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Уменьшает расход заряда батареи и улучшает работу сети"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Если этот режим активирован, MAC-адрес устройства может меняться при каждом подключении к сети, в которой возможно создание случайных MAC-адресов."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Сеть с тарификацией трафика"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Сеть без тарификации трафика"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Размер буфера журнала"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 7e46a68..ffe6472 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"නොරැහැන් සංදර්ශක සහතිකය"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"විස්තරාත්මක Wi‑Fi ලොග් කිරීම සබල කරන්න"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ස්කෑන් අවකරණය"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi අඛණ්ඩ නොවන MAC සසම්භාවීකරණය"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"ජංගම දත්ත සැමවිට ක්‍රියාකාරීය"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ටෙදරින් දෘඪාංග ත්වරණය"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"බැටරි බැසීම අඩු කරන අතර ජාල කාර්ය සාධනය වැඩි දියුණු කරයි"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"මෙම ප්‍රකාරය සබල විට, මෙම උපාංගයේ MAC ලිපිනය එය MAC සසම්භාවීකරණය සබල කර ඇති ජාලයකට සම්බන්ධ වන එක් එක් අවස්ථාවල වෙනස් විය හැකිය."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"මනිනු ලැබේ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"මනින්නේ නැත"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ලෝගයේ අන්තරාවක ප්‍රමාණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 199906e..7e46d1c 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikácia bezdrôtového zobrazenia"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné denníky Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pribrzdiť vyhľadávanie sietí Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Randomizácia dočasnej adresy MAC siete Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilné dáta ponechať vždy aktívne"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardvérová akcelerácia tetheringu"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Znižuje používanie batérie a zlepšuje výkon siete"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Keď je tento režim aktivovaný, adresa MAC tohto zariadenia sa môže pri každom pripojení k sieti s aktivovanou randomizáciou adries MAC zmeniť."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Merané"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez merania dát"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávacia pamäť nástroja denníkov"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 43fb928..d498ac2 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Potrdilo brezžičnega zaslona"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogoči podrobno zapisovanje dnevnika za Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Omejevanje iskanja omrežij Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Dodeljevanje nestalnega naključnega naslova MAC za Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaži možnosti za potrdilo brezžičnega zaslona."</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI."</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije baterije in izboljša delovanje omrežja."</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Ko je ta način omogočen, se lahko naslov MAC te naprave spremeni vsakič, ko se naprava poveže v omrežje z omogočenim dodeljevanjem naključnega naslova MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Omejen prenos podatkov"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Z neomejenim prenosom podatkov"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Velikosti medpomnilnikov zapisovalnika dnevnika"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b004082..c088d85 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikimi i ekranit pa tel"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivizo hyrjen Wi-Fi Verbose"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Përshpejtimi i skanimit të Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Renditje e rastësishme jo e përhershme e MAC për Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Të dhënat celulare gjithmonë aktive"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Përshpejtimi i harduerit për ndarjen e lidhjes (internet)"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Shfaq opsionet për certifikimin e ekranit pa tel"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zvogëlon shkarkimin e baterisë dhe përmirëson cilësinë e funksionimit të rrjetit"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kur ky modalitet është i aktivizuar, adresa MAC e kësaj pajisjeje mund të ndryshojë çdo herë që lidhet me një rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Me matje"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Pa matje"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Madhësitë e regjistruesit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index dd3ab9b..5bb65e5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Сертификација бежичног екрана"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Омогући детаљнију евиденцију за Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Успоравање WiFi скенирања"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Насумично разврставање MAC адреса по WiFi-ју са прекидима"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилни подаци су увек активни"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско убрзање привезивања"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Приказује опције за сертификацију бежичног екрана"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Смањује потрошњу батерије и побољшава учинак мреже"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Када је овај режим омогућен, MAC адреса овог уређаја може да се промени сваки пут када се повеже са мрежом на којој је омогућено насумично разврставање MAC адреса."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Са ограничењем"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничења"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Величине бафера података у програму за евидентирање"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 0fa10c9..cee8d53 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certifiering för wifi-skärmdelning"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivera utförlig loggning för wifi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begränsning av wifi-sökning"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Slumpgenerering av icke-beständig MAC för wifi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata alltid aktiverad"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvaruacceleration för internetdelning"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Visa certifieringsalternativ för wifi-skärmdelning"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Öka loggningsnivån för wifi, visa per SSID RSSI i Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sänker batteriförbrukningen och förbättrar nätverksprestandan"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"När det här läget är aktiverat kan enhetens MAC-adress ändras varje gång den ansluts till ett nätverk där slumpgenerering av MAC-adress har aktiverats."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Med datapriser"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Utan datapriser"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Buffertstorlekar för logg"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 58428cd..4748118 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Chaguo za cheti cha kuonyesha pasiwaya"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Washa Uwekaji kumbukumbu za WiFi kutumia Sauti"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Kudhibiti utafutaji wa Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Kuweka kwa unasibu anwani za MAC zisizo na muunganisho endelevu wa Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Iendelee kutumia data ya simu"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Hupunguza matumizi ya chaji ya betri na kuboresha utendaji wa mtandao"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wakati hali hii imewashwa, huenda anwani ya MAC ya kifaa hiki ikabadilika kila wakati kinapounganisha kwenye mtandao ambapo kipengele cha unasibu wa MAC kimewashwa."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Mtandao unapima data"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mtandao usiopima data"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Ukubwa wa kiweka bafa ya kumbukumbu"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 4234d8f..2f25722 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"வயர்லெஸ் காட்சிக்கான சான்றிதழ்"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"வைஃபை அதிவிவர நுழைவை இயக்கு"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"வைஃபை ஸ்கேனிங்கை வரம்பிடுதல்"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"வைஃபையில் MAC முகவரியை ரேண்டம் ஆக்குதல்"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"மொபைல் டேட்டாவை எப்போதும் இயக்கத்திலேயே வை"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"இந்தப் பயன்முறை இயக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தின் MAC முகவரி ஒவ்வொரு முறை \'MAC முகவரியை ரேண்டம் ஆக்குதல்\' இயக்கப்பட்டிருக்கும் நெட்வொர்க்குடன் இணைக்கப்படும்போதும் மாறக்கூடும்."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"கட்டண நெட்வொர்க்"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"கட்டணமில்லா நெட்வொர்க்"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"லாகர் பஃபர் அளவுகள்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 081fe92..db8edf7 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"వైర్‌లెస్ డిస్‌ప్లే సర్టిఫికేషన్‌"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi విశదీకృత లాగింగ్‌ను ప్రారంభించండి"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi స్కాన్ కుదింపు"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi నిరంతరం కాని MAC ర్యాండమైజేషన్"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"మొబైల్ డేటాని ఎల్లప్పుడూ యాక్టివ్‌గా ఉంచు"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"టెథెరింగ్ హార్డ్‌వేర్ వేగవృద్ధి"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు  చూపించు"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్‌లెస్ డిస్‌ప్లే సర్టిఫికేషన్ ఆప్షన్‌లను చూపు"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి &amp; నెట్‌వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్‌ను ఎనేబుల్ చేసిన నెట్‌వర్క్‌తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్‌ను మారవచ్చు."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"గణించబడుతోంది"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"గణించబడటం లేదు"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"లాగర్ బఫర్ సైజ్‌లు"</string>
@@ -491,7 +489,7 @@
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"సక్రియ ఇన్‌పుట్ పద్ధతులు"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"సిస్టమ్ భాషలను ఉపయోగించు"</string>
     <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> యొక్క సెట్టింగ్‌లను తెరవడం విఫలమైంది"</string>
-    <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> అనువర్తనంలో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
+    <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> యాప్‌లో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"గమనిక: రీబూట్ చేసాక, మీరు మీ ఫోన్‌ను అన్‌లాక్ చేసే వరకు ఈ యాప్ ప్రారంభం కాదు"</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"IMS నమోదు స్థితి"</string>
     <string name="ims_reg_status_registered" msgid="884916398194885457">"నమోదు చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 7edc67f..494a690 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"การรับรองการแสดงผลแบบไร้สาย"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"เปิดใช้การบันทึกรายละเอียด Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"การควบคุมการสแกนหา Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"การสุ่ม MAC ที่มี Wi-Fi ไม่ถาวร"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"เปิดใช้เน็ตมือถือเสมอ"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"แสดงตัวเลือกสำหรับการรับรองการแสดงผลแบบไร้สาย"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายซึ่งเปิดใช้การสุ่ม MAC"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"แบบจำกัดปริมาณ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 058decc..a6f93c5 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certification ng wireless display"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"I-enable ang Pagla-log sa Wi‑Fi Verbose"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pag-throttle ng pag-scan ng Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Pag-randomize ng MAC na hindi persistent sa Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Palaging aktibo ang mobile data"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardware acceleration para sa pag-tether"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Binabawasan ang pagkaubos ng baterya at pinapahusay ang performance ng network"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Kapag naka-enable ang mode na ito, puwedeng magbago ang MAC address ng device na ito sa tuwing kokonekta ito sa isang network na may naka-enable na pag-randomize ng MAC."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Nakametro"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Hindi Nakametro"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Mga laki ng buffer ng Logger"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index d1d760e..e1d9831 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Kablosuz ekran sertifikası"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Kablosuz Ayrıntılı Günlük Kaydını etkinleştir"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Kablosuz ağ taramasını kısma"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Kablosuz kalıcı olmayan MAC rastgele hale getirme süreci"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil veri her zaman etkin"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering donanım hızlandırıcısı"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Pili daha az harcar ve ağ performansını iyileştirir"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu mod etkinleştirildiğinde, bu cihaz MAC rastgele hale getirme işlevi açık olan bir ağa her bağlandığında cihazın MAC adresi değişebilir."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Sayaçlı"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sayaçsız"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Günlük Kaydedici arabellek boyutları"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 8962936..5b96e27 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Сертифікація бездрот. екрана"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Докладний запис у журнал Wi-Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Зменшити радіус пошуку мереж Wi‑Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Випадкові MAC-адреси в мережі Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Не вимикати мобільне передавання даних"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратне прискорення під час використання телефона в режимі модема"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показати параметри сертифікації бездротового екрана"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зменшує споживання заряду акумулятора й підвищує ефективність роботи мережі"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Коли цей режим увімкнено, MAC-адреса пристрою може змінюватися щоразу, коли він підключається до мережі з випадковими MAC-адресами."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"З тарифікацією трафіку"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без тарифікації трафіку"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Розміри буфера журналу"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index d5314df..af60e9d 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"وائرلیس ڈسپلے سرٹیفیکیشن"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"‏Wi‑Fi وربوس لاگنگ فعال کریں"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"‏Wi‑Fi اسکین کو زبردستی روکا جا رہا ہے"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"‏Wi-Fi غیر مستقل MAC کی رینڈمائزیشن"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"ٹیدرنگ ہارڈویئر سرعت کاری"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‏Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"بیٹری ڈرین کم کرتا ہے اور نیٹ ورک کارکردگی کو بہتر بناتا ہے"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"‏اس وضع کے فعال ہونے پر اس آلے کا MAC پتہ ہر بار تبدیل ہو سکتا ہے جب بھی یہ کسی ایسے نیٹ ورک سے منسلک ہوتا ہے جس میں MAC رینڈمائزیشن فعال ہو۔"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"میٹرڈ"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"غیر میٹر شدہ"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"لاگر بفر کے سائز"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3708c09..53f8520 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz monitor sertifikatlari"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Batafsil Wi-Fi jurnali"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi tarmoqni taqsimlab skanlash"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi MAC manzilini muddatli tasodiflash"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil internet doim yoniq tursin"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Modem rejimida apparatli tezlashtirish"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya sarfini tejaydi va tarmoq samaradorligini oshiradi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Bu rejim yoqilganda qurilmaning MAC manzili tasodifiy MAC manzillar yaratish imkoniyati mavjud tarmoqqa har safar ulanganda almashishi mumkin."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Trafik hisoblanadigan tarmoq"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Trafik hisobi yuritilmaydigan tarmoq"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi hajmi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b7faf0a..bf4ab28 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Chứng nhận hiển thị không dây"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Bật ghi nhật ký chi tiết Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Hạn chế quét tìm Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Tạo địa chỉ MAC ngẫu nhiên, không cố định mỗi khi kết nối Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dữ liệu di động luôn hoạt động"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tăng tốc phần cứng khi chia sẻ Internet"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiện các thiết bị Bluetooth không có tên"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Giảm hao pin và cải thiện hiệu suất mạng"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Khi bật chế độ này, địa chỉ MAC của thiết bị này có thể thay đổi mỗi lần thiết bị kết nối với mạng đã bật chế độ tạo địa chỉ MAC ngẫu nhiên."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Đo lượng dữ liệu"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Không đo lượng dữ liệu"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Kích thước bộ đệm của trình ghi nhật ký"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index dc31eb3..aac8eed 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"无线显示认证"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"启用 WLAN 详细日志记录功能"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"WLAN 扫描调节"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"为 WLAN 热点随机生成非持久性 MAC 地址"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"始终开启移动数据网络"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"网络共享硬件加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"提升 WLAN 日志记录级别(在 WLAN 选择器中显示每个 SSID 的 RSSI)"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗电量以及改善网络性能"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"启用此模式后,这台设备每次连接到已启用随机生成 MAC 地址功能的网络时,其 MAC 地址都可能会更改。"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"按流量计费"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"不按流量计费"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"日志记录器缓冲区大小"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 78002d4..78b57cc 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 掃瞄限流"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"一律保持啟用流動數據"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"網絡共享硬件加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"減低耗電量並改善網絡表現"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"啟用此模式後,每次連接至已啟用 MAC 隨機處理的網絡時,此裝置的 MAC 位址都可能會變更。"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"按用量收費"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"不限數據用量收費"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 1a26b92..637714a 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄設定"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi 掃描調節"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wi‑Fi 非持續性隨機 MAC 位址"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"行動數據連線一律保持啟用狀態"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"網路共用硬體加速"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細記錄"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗電量以及改善網路效能"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"這個模式啟用後,每當這部裝置連線到已啟用隨機 MAC 位址的網路時,裝置的 MAC 位址可能都會改變。"</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"計量付費"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"非計量付費"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index ad47a80..ae262fc 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -252,8 +252,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Ukunikezwa isitifiketi sokubukeka okungenantambo"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Nika amandlaukungena kwe-Wi-Fi Verbose"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"I-throttling yokuskena kwe-Wi-Fi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization (7482769677894247316) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Okungahleliwe kwe-MAC engaphikeleli ye-Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Idatha yeselula ihlala isebenza"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"I-Tethering hardware acceleration"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
@@ -285,8 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Yehlisa ukuphela kwebhethri futhi ithuthukise ukusebenza kwenethiwekhi"</string>
-    <!-- no translation found for wifi_non_persistent_mac_randomization_summary (2159794543105053930) -->
-    <skip />
+    <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Uma le modi inikwe amandla, ikheli le-MAC lale divayisi lingashintsha njalo uma ixhuma kunethiwekhi ene-MAC engahleliwe enikwe amandla."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Kulinganisiwe"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Akulinganiselwa"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Amasayizi weloga ngebhafa"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
index bd9e0d3..7275d6b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerFactory.java
@@ -18,6 +18,9 @@
 
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 
+import static com.android.settingslib.enterprise.ActionDisabledLearnMoreButtonLauncher.DEFAULT_RESOLVE_ACTIVITY_CHECKER;
+import static com.android.settingslib.enterprise.ManagedDeviceActionDisabledByAdminController.DEFAULT_FOREGROUND_USER_CHECKER;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.hardware.biometrics.BiometricAuthenticator;
@@ -43,7 +46,11 @@
         } else if (isFinancedDevice(context)) {
             return new FinancedDeviceActionDisabledByAdminController(stringProvider);
         } else {
-            return new ManagedDeviceActionDisabledByAdminController(stringProvider, userHandle);
+            return new ManagedDeviceActionDisabledByAdminController(
+                    stringProvider,
+                    userHandle,
+                    DEFAULT_FOREGROUND_USER_CHECKER,
+                    DEFAULT_RESOLVE_ACTIVITY_CHECKER);
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
index 4114879..f9d3aaf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
@@ -22,6 +22,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -34,6 +35,17 @@
  */
 public abstract class ActionDisabledLearnMoreButtonLauncher {
 
+    public static ResolveActivityChecker DEFAULT_RESOLVE_ACTIVITY_CHECKER =
+            (packageManager, url, userHandle) -> packageManager.resolveActivityAsUser(
+                    createLearnMoreIntent(url),
+                    PackageManager.MATCH_DEFAULT_ONLY,
+                    userHandle.getIdentifier()) != null;
+
+    interface ResolveActivityChecker {
+        boolean canResolveActivityAsUser(
+                PackageManager packageManager, String url, UserHandle userHandle);
+    }
+
     /**
      * Sets up a "learn more" button which shows a screen with device policy settings
      */
@@ -111,6 +123,14 @@
         finishSelf();
     }
 
+    protected final boolean canLaunchHelpPage(
+            PackageManager packageManager,
+            String url,
+            UserHandle userHandle,
+            ResolveActivityChecker resolveActivityChecker) {
+        return resolveActivityChecker.canResolveActivityAsUser(packageManager, url, userHandle);
+    }
+
     private void showAdminPolicies(Context context, EnforcedAdmin enforcedAdmin) {
         if (enforcedAdmin.component != null) {
             launchShowAdminPolicies(context, enforcedAdmin.user, enforcedAdmin.component);
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
index 1472980..364698f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
@@ -23,6 +23,7 @@
 import android.util.Log;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.RestrictedLockUtils;
 
@@ -32,10 +33,12 @@
 
     // These MUST not change, as they are the stable API between here and device admin specified
     // by the component below.
-    private static final String ACTION_LEARN_MORE =
-            "android.intent.action.MANAGE_RESTRICTED_SETTING";
-    private static final String EXTRA_SETTING_KEY = "extra_setting";
-    private static final String EXTRA_SETTING_VALUE = "biometric_disabled_by_admin_controller";
+    @VisibleForTesting
+    static final String ACTION_LEARN_MORE = "android.intent.action.MANAGE_RESTRICTED_SETTING";
+    @VisibleForTesting
+    static final String EXTRA_SETTING_KEY = "extra_setting";
+    @VisibleForTesting
+    static final String EXTRA_SETTING_VALUE = "biometric_disabled_by_admin_controller";
 
     BiometricActionDisabledByAdminController(
             DeviceAdminStringProvider stringProvider) {
@@ -64,9 +67,9 @@
         return (dialog, which) -> {
             Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
             final Intent intent = new Intent(ACTION_LEARN_MORE)
-                    .setComponent(enforcedAdmin.component)
                     .putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE)
-                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                    .setPackage(enforcedAdmin.component.getPackageName());
             context.startActivity(intent);
         };
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
index 93e811d..c2034f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
@@ -20,13 +20,14 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
 
 import androidx.annotation.Nullable;
 
-import java.util.Objects;
+import com.android.settingslib.enterprise.ActionDisabledLearnMoreButtonLauncher.ResolveActivityChecker;
 
 
 /**
@@ -35,17 +36,37 @@
 final class ManagedDeviceActionDisabledByAdminController
         extends BaseActionDisabledByAdminController {
 
-    private final UserHandle mUserHandle;
+    interface ForegroundUserChecker {
+        boolean isUserForeground(Context context, UserHandle userHandle);
+    }
+
+    public final static ForegroundUserChecker DEFAULT_FOREGROUND_USER_CHECKER =
+            ManagedDeviceActionDisabledByAdminController::isUserForeground;
+
+    /**
+     * The {@link UserHandle} which is preferred for launching the web help page in
+     * <p>If not able to launch the web help page in this user, the current user will be used as
+     * fallback instead. If the current user cannot open it either, the admin policies page will
+     * be used instead.
+     */
+    private final UserHandle mPreferredUserHandle;
+
+    private final ForegroundUserChecker mForegroundUserChecker;
+    private final ResolveActivityChecker mResolveActivityChecker;
 
     /**
      * Constructs a {@link ManagedDeviceActionDisabledByAdminController}
-     * @param userHandle - user on which to launch the help web page, if necessary
+     * @param preferredUserHandle - user on which to launch the help web page, if necessary
      */
     ManagedDeviceActionDisabledByAdminController(
             DeviceAdminStringProvider stringProvider,
-            UserHandle userHandle) {
+            UserHandle preferredUserHandle,
+            ForegroundUserChecker foregroundUserChecker,
+            ResolveActivityChecker resolveActivityChecker) {
         super(stringProvider);
-        mUserHandle = requireNonNull(userHandle);
+        mPreferredUserHandle = requireNonNull(preferredUserHandle);
+        mForegroundUserChecker = requireNonNull(foregroundUserChecker);
+        mResolveActivityChecker = requireNonNull(resolveActivityChecker);
     }
 
     @Override
@@ -53,14 +74,52 @@
         assertInitialized();
 
         String url = mStringProvider.getLearnMoreHelpPageUrl();
-        if (TextUtils.isEmpty(url)) {
+
+        if (!TextUtils.isEmpty(url)
+                && canLaunchHelpPageInPreferredOrCurrentUser(context, url, mPreferredUserHandle)) {
+            setupLearnMoreButtonToLaunchHelpPage(context, url, mPreferredUserHandle);
+        } else {
             mLauncher.setupLearnMoreButtonToShowAdminPolicies(context, mEnforcementAdminUserId,
                     mEnforcedAdmin);
-        } else {
-            mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, mUserHandle);
         }
     }
 
+    private boolean canLaunchHelpPageInPreferredOrCurrentUser(
+            Context context, String url, UserHandle preferredUserHandle) {
+        PackageManager packageManager = context.getPackageManager();
+        if (mLauncher.canLaunchHelpPage(
+                packageManager, url, preferredUserHandle, mResolveActivityChecker)
+                && mForegroundUserChecker.isUserForeground(context, preferredUserHandle)) {
+            return true;
+        }
+        return mLauncher.canLaunchHelpPage(
+                packageManager, url, context.getUser(), mResolveActivityChecker);
+    }
+
+    /**
+     * Sets up the "Learn more" button to launch the web help page in the {@code
+     * preferredUserHandle} user. If not possible to launch it there, it sets up the button to
+     * launch it in the current user instead.
+     */
+    private void setupLearnMoreButtonToLaunchHelpPage(
+            Context context, String url, UserHandle preferredUserHandle) {
+        PackageManager packageManager = context.getPackageManager();
+        if (mLauncher.canLaunchHelpPage(
+                packageManager, url, preferredUserHandle, mResolveActivityChecker)
+                && mForegroundUserChecker.isUserForeground(context, preferredUserHandle)) {
+            mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, preferredUserHandle);
+        }
+        if (mLauncher.canLaunchHelpPage(
+                packageManager, url, context.getUser(), mResolveActivityChecker)) {
+            mLauncher.setupLearnMoreButtonToLaunchHelpPage(context, url, context.getUser());
+        }
+    }
+
+    private static boolean isUserForeground(Context context, UserHandle userHandle) {
+        return context.createContextAsUser(userHandle, /* flags= */ 0)
+                .getSystemService(UserManager.class).isUserForeground();
+    }
+
     @Override
     public String getAdminSupportTitle(@Nullable String restriction) {
         if (restriction == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 79446e4..ed8d524 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -44,6 +44,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.RequiresApi;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -56,6 +58,7 @@
 /**
  * InfoMediaManager provide interface to get InfoMediaDevice list.
  */
+@RequiresApi(Build.VERSION_CODES.R)
 public class InfoMediaManager extends MediaManager {
 
     private static final String TAG = "InfoMediaManager";
@@ -145,9 +148,16 @@
     }
 
     private RoutingSessionInfo getRoutingSessionInfo() {
-        final List<RoutingSessionInfo> sessionInfos =
-                mRouterManager.getRoutingSessions(mPackageName);
+        return getRoutingSessionInfo(mPackageName);
+    }
 
+    private RoutingSessionInfo getRoutingSessionInfo(String packageName) {
+        final List<RoutingSessionInfo> sessionInfos =
+                mRouterManager.getRoutingSessions(packageName);
+
+        if (sessionInfos == null || sessionInfos.isEmpty()) {
+            return null;
+        }
         return sessionInfos.get(sessionInfos.size() - 1);
     }
 
@@ -367,33 +377,13 @@
     }
 
     boolean shouldDisableMediaOutput(String packageName) {
-        boolean shouldDisableMediaOutput = false;
         if (TextUtils.isEmpty(packageName)) {
             Log.w(TAG, "shouldDisableMediaOutput() package name is null or empty!");
-            return false;
+            return true;
         }
-        final List<MediaRoute2Info> infos = mRouterManager.getTransferableRoutes(packageName);
-        if (infos.size() == 1) {
-            final MediaRoute2Info info = infos.get(0);
-            final int deviceType = info.getType();
-            switch (deviceType) {
-                case TYPE_UNKNOWN:
-                case TYPE_REMOTE_TV:
-                case TYPE_REMOTE_SPEAKER:
-                case TYPE_GROUP:
-                    shouldDisableMediaOutput = true;
-                    break;
-                default:
-                    shouldDisableMediaOutput = false;
-                    break;
-            }
-        }
-        if (DEBUG) {
-            Log.d(TAG, "shouldDisableMediaOutput() MediaRoute2Info size : " + infos.size()
-                    + ", package name : " + packageName + ", shouldDisableMediaOutput : "
-                    + shouldDisableMediaOutput);
-        }
-        return shouldDisableMediaOutput;
+
+        // Disable when there is no transferable route
+        return mRouterManager.getTransferableRoutes(packageName).isEmpty();
     }
 
     @TargetApi(Build.VERSION_CODES.R)
@@ -456,7 +446,7 @@
     }
 
     private void buildAvailableRoutes() {
-        for (MediaRoute2Info route : mRouterManager.getTransferableRoutes(mPackageName)) {
+        for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
             if (DEBUG) {
                 Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
                         + route.getVolume() + ", type : " + route.getType());
@@ -465,6 +455,29 @@
         }
     }
 
+    private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+        final List<MediaRoute2Info> infos = new ArrayList<>();
+        RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
+        if (routingSessionInfo != null) {
+            infos.addAll(mRouterManager.getSelectedRoutes(routingSessionInfo));
+        }
+        final List<MediaRoute2Info> transferableRoutes =
+                mRouterManager.getTransferableRoutes(packageName);
+        for (MediaRoute2Info transferableRoute : transferableRoutes) {
+            boolean alreadyAdded = false;
+            for (MediaRoute2Info mediaRoute2Info : infos) {
+                if (TextUtils.equals(transferableRoute.getId(), mediaRoute2Info.getId())) {
+                    alreadyAdded = true;
+                    break;
+                }
+            }
+            if (!alreadyAdded) {
+                infos.add(transferableRoute);
+            }
+        }
+        return infos;
+    }
+
     @VisibleForTesting
     void addMediaDevice(MediaRoute2Info route) {
         final int deviceType = route.getType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index a8da2c0..22001c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -22,11 +22,13 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.media.RoutingSessionInfo;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.A2dpProfile;
@@ -49,6 +51,7 @@
 /**
  * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice.
  */
+@RequiresApi(Build.VERSION_CODES.R)
 public class LocalMediaManager implements BluetoothCallback {
     private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
     private static final String TAG = "LocalMediaManager";
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index 97e6d50..ed198fa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -38,6 +38,7 @@
 import com.android.settingslib.core.lifecycle.events.OnStop;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -158,6 +159,7 @@
     }
 
     @Test
+    @Ignore("b/188888268")
     public void runThroughActivityLifecycles_shouldObserveEverything() {
         ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class);
         TestActivity activity = ac.setup().get();
@@ -179,6 +181,7 @@
     }
 
     @Test
+    @Ignore("b/188888268")
     public void runThroughDialogFragmentLifecycles_shouldObserveEverything() {
         final TestDialogFragment fragment = new TestDialogFragment();
         FragmentController.setupFragment(fragment);
@@ -202,6 +205,7 @@
     }
 
     @Test
+    @Ignore("b/188888268")
     public void runThroughFragmentLifecycles_shouldObserveEverything() {
         final TestFragment fragment = new TestFragment();
         FragmentController.setupFragment(fragment);
@@ -241,6 +245,7 @@
     }
 
     @Test
+    @Ignore("b/188888268")
     public void onOptionItemSelectedShortCircuitsIfAnObserverHandlesTheMenuItem() {
         final TestFragment fragment = new TestFragment();
         FragmentController.setupFragment(fragment);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
index 766c2f5..c41f4db 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminControllerTest.java
@@ -22,7 +22,7 @@
 
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.assertSame;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -39,41 +39,49 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public class BiometricActionDisabledByAdminControllerTest {
 
-    private final ActionDisabledByAdminControllerTestUtils mTestUtils =
-            new ActionDisabledByAdminControllerTestUtils();
-    private final BiometricActionDisabledByAdminController mController =
-            new BiometricActionDisabledByAdminController(DEFAULT_DEVICE_ADMIN_STRING_PROVIDER);
+    @Mock
+    private Context mContext;
+
+    private ActionDisabledByAdminControllerTestUtils mTestUtils;
+    private BiometricActionDisabledByAdminController mController;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTestUtils = new ActionDisabledByAdminControllerTestUtils();
+
+        mController = new BiometricActionDisabledByAdminController(
+                DEFAULT_DEVICE_ADMIN_STRING_PROVIDER);
         mController.initialize(mTestUtils.createLearnMoreButtonLauncher());
         mController.updateEnforcedAdmin(ENFORCED_ADMIN, ENFORCEMENT_ADMIN_USER_ID);
     }
 
     @Test
     public void buttonClicked() {
-        Context context = mock(Context.class);
         ComponentName componentName = mock(ComponentName.class);
         RestrictedLockUtils.EnforcedAdmin enforcedAdmin = new RestrictedLockUtils.EnforcedAdmin(
                 componentName, new UserHandle(UserHandle.myUserId()));
 
         DialogInterface.OnClickListener listener =
-                mController.getPositiveButtonListener(context, enforcedAdmin);
+                mController.getPositiveButtonListener(mContext, enforcedAdmin);
         assertNotNull("Biometric Controller must supply a non-null listener", listener);
         listener.onClick(mock(DialogInterface.class), 0 /* which */);
 
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(context).startActivity(intentCaptor.capture());
-        assertEquals("android.settings.LEARN_MORE",
+        verify(mContext).startActivity(intentCaptor.capture());
+        assertEquals(BiometricActionDisabledByAdminController.ACTION_LEARN_MORE,
                 intentCaptor.getValue().getAction());
-        assertTrue("from_biometric_setup", intentCaptor.getValue()
-                .getBooleanExtra("from_biometric_setup", false));
-        assertEquals(componentName, intentCaptor.getValue().getComponent());
+        assertEquals(BiometricActionDisabledByAdminController.EXTRA_SETTING_VALUE,
+                intentCaptor.getValue().getStringExtra(
+                        BiometricActionDisabledByAdminController.EXTRA_SETTING_KEY));
+        assertSame(componentName, intentCaptor.getValue().getComponent());
     }
-
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
index d9be4f3..509e12d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
@@ -30,6 +30,8 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
 import android.os.UserManager;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -45,9 +47,11 @@
 @RunWith(RobolectricTestRunner.class)
 public class ManagedDeviceActionDisabledByAdminControllerTest {
 
+    private static UserHandle MANAGED_USER = UserHandle.of(123);
     private static final String RESTRICTION = UserManager.DISALLOW_ADJUST_VOLUME;
     private static final String EMPTY_URL = "";
     private static final String SUPPORT_TITLE_FOR_RESTRICTION = DISALLOW_ADJUST_VOLUME_TITLE;
+    public static final ResolveInfo TEST_RESULT_INFO = new ResolveInfo();
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private final Activity mActivity = ActivityController.of(new Activity()).get();
@@ -60,8 +64,21 @@
     }
 
     @Test
-    public void setupLearnMoreButton_validUrl_negativeButtonSet() {
-        ManagedDeviceActionDisabledByAdminController controller = createController(URL);
+    public void setupLearnMoreButton_noUrl_negativeButtonSet() {
+        ManagedDeviceActionDisabledByAdminController controller = createController(EMPTY_URL);
+
+        controller.setupLearnMoreButton(mContext);
+
+        mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES);
+    }
+
+    @Test
+    public void setupLearnMoreButton_validUrl_foregroundUser_launchesHelpPage() {
+        ManagedDeviceActionDisabledByAdminController controller = createController(
+                URL,
+                /* isUserForeground= */ true,
+                /* preferredUserHandle= */ MANAGED_USER,
+                /* userContainingBrowser= */ MANAGED_USER);
 
         controller.setupLearnMoreButton(mContext);
 
@@ -69,8 +86,38 @@
     }
 
     @Test
-    public void setupLearnMoreButton_noUrl_negativeButtonSet() {
-        ManagedDeviceActionDisabledByAdminController controller = createController(EMPTY_URL);
+    public void setupLearnMoreButton_validUrl_browserInPreferredUser_notForeground_showsAdminPolicies() {
+        ManagedDeviceActionDisabledByAdminController controller = createController(
+                URL,
+                /* isUserForeground= */ false,
+                /* preferredUserHandle= */ MANAGED_USER,
+                /* userContainingBrowser= */ MANAGED_USER);
+
+        controller.setupLearnMoreButton(mContext);
+
+        mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES);
+    }
+
+    @Test
+    public void setupLearnMoreButton_validUrl_browserInCurrentUser_launchesHelpPage() {
+        ManagedDeviceActionDisabledByAdminController controller = createController(
+                URL,
+                /* isUserForeground= */ false,
+                /* preferredUserHandle= */ MANAGED_USER,
+                /* userContainingBrowser= */ mContext.getUser());
+
+        controller.setupLearnMoreButton(mContext);
+
+        mTestUtils.assertLearnMoreAction(LEARN_MORE_ACTION_LAUNCH_HELP_PAGE);
+    }
+
+    @Test
+    public void setupLearnMoreButton_validUrl_browserNotOnAnyUser_showsAdminPolicies() {
+        ManagedDeviceActionDisabledByAdminController controller = createController(
+                URL,
+                /* isUserForeground= */ false,
+                /* preferredUserHandle= */ MANAGED_USER,
+                /* userContainingBrowser= */ null);
 
         controller.setupLearnMoreButton(mContext);
 
@@ -110,13 +157,33 @@
     }
 
     private ManagedDeviceActionDisabledByAdminController createController() {
-        return createController(/* url= */ null);
+        return createController(
+                /* url= */ null,
+                /* foregroundUserChecker= */ true,
+                mContext.getUser(),
+                /* userContainingBrowser= */ null);
     }
 
     private ManagedDeviceActionDisabledByAdminController createController(String url) {
+        return createController(
+                url,
+                /* foregroundUserChecker= */ true,
+                mContext.getUser(),
+                /* userContainingBrowser= */ null);
+    }
+
+    private ManagedDeviceActionDisabledByAdminController createController(
+            String url,
+            boolean isUserForeground,
+            UserHandle preferredUserHandle,
+            UserHandle userContainingBrowser) {
         ManagedDeviceActionDisabledByAdminController controller =
                 new ManagedDeviceActionDisabledByAdminController(
-                        new FakeDeviceAdminStringProvider(url), mContext.getUser());
+                        new FakeDeviceAdminStringProvider(url),
+                        preferredUserHandle,
+                        /* foregroundUserChecker= */ (context, userHandle) -> isUserForeground,
+                        /* resolveActivityChecker= */ (packageManager, __, userHandle) ->
+                                userHandle.equals(userContainingBrowser));
         controller.initialize(mTestUtils.createLearnMoreButtonLauncher());
         controller.updateEnforcedAdmin(ENFORCED_ADMIN, ENFORCEMENT_ADMIN_USER_ID);
         return controller;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 58ca734..0d03f33 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -27,7 +27,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -108,7 +107,7 @@
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(routes);
+        mShadowRouter2Manager.setTransferableRoutes(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
         assertThat(mediaDevice).isNull();
@@ -159,7 +158,7 @@
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(routes);
+        mShadowRouter2Manager.setTransferableRoutes(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
         assertThat(mediaDevice).isNull();
@@ -195,7 +194,7 @@
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(routes);
+        mShadowRouter2Manager.setTransferableRoutes(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
         assertThat(mediaDevice).isNull();
@@ -618,7 +617,7 @@
 
         final List<MediaRoute2Info> routes = new ArrayList<>();
         routes.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(routes);
+        mShadowRouter2Manager.setTransferableRoutes(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
         assertThat(mediaDevice).isNull();
@@ -728,9 +727,8 @@
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
         final List<MediaRoute2Info> infos = new ArrayList<>();
         infos.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(infos);
+        mShadowRouter2Manager.setTransferableRoutes(infos);
 
-        when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
         when(info.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
 
         assertThat(mInfoMediaManager.shouldDisableMediaOutput("test")).isTrue();
@@ -741,9 +739,8 @@
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
         final List<MediaRoute2Info> infos = new ArrayList<>();
         infos.add(info);
-        mShadowRouter2Manager.setAvailableRoutes(infos);
+        mShadowRouter2Manager.setTransferableRoutes(infos);
 
-        when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
         when(info.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
 
         assertThat(mInfoMediaManager.shouldDisableMediaOutput("test")).isFalse();
@@ -757,9 +754,8 @@
         final List<MediaRoute2Info> infos = new ArrayList<>();
         infos.add(info);
         infos.add(info2);
-        mShadowRouter2Manager.setAvailableRoutes(infos);
+        mShadowRouter2Manager.setTransferableRoutes(infos);
 
-        when(mRouterManager.getAvailableRoutes(anyString())).thenReturn(infos);
         when(info.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
         when(info2.getType()).thenReturn(TYPE_REMOTE_SPEAKER);
 
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
index 5bb5500..5959863 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java
@@ -85,4 +85,13 @@
         return (ShadowRouter2Manager) Shadow.extract(
                 MediaRouter2Manager.getInstance(RuntimeEnvironment.application));
     }
+
+    @Implementation
+    protected List<MediaRoute2Info> getTransferableRoutes(String packageName) {
+        return mAvailableRoutes;
+    }
+
+    public void setTransferableRoutes(List<MediaRoute2Info> infos) {
+        mAvailableRoutes = infos;
+    }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index ab6a8a9..fe48575 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -20,6 +20,7 @@
 import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.PERCENTAGE_INTEGER_VALIDATOR;
 import static android.view.Display.HdrCapabilities.HDR_TYPES;
@@ -116,6 +117,11 @@
         VALIDATORS.put(Global.CLOCKWORK_SYSUI_MAIN_ACTIVITY_NAME, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.CLOCKWORK_SYSUI_PACKAGE_NAME, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.CLOCKWORK_HOME_READY, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.ENABLE_TARE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.ENABLE_TARE_ALARM_MANAGER, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.ENABLE_TARE_JOB_SCHEDULER, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.TARE_ALARM_MANAGER_CONSTANTS, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.TARE_JOB_SCHEDULER_CONSTANTS, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.PRIVATE_DNS_MODE, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.PRIVATE_DNS_SPECIFIER, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.SOFT_AP_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
@@ -159,12 +165,12 @@
                             String.valueOf(Global.Wearable.RETAIL_MODE_RETAIL)
                         }));
         VALIDATORS.put(
-                Global.Wearable.PLAY_STORE_AVAILABILITY,
+                Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
                 new DiscreteValueValidator(
                         new String[] {
-                            String.valueOf(Global.Wearable.PLAY_STORE_AVAILABLE),
-                            String.valueOf(Global.Wearable.PLAY_STORE_UNAVAILABLE),
-                            String.valueOf(Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN)
+                            String.valueOf(Global.Wearable.PHONE_PLAY_STORE_AVAILABLE),
+                            String.valueOf(Global.Wearable.PHONE_PLAY_STORE_UNAVAILABLE),
+                            String.valueOf(Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN)
                         }));
         VALIDATORS.put(
                 Global.Wearable.BUG_REPORT,
@@ -296,6 +302,21 @@
         VALIDATORS.put(Global.Wearable.OEM_SETUP_VERSION, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.MASTER_GESTURES_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.UNGAZE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.BATTERY_SAVER_MODE,
+                new DiscreteValueValidator(
+                        new String[] {
+                                String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_NONE),
+                                String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_LIGHT),
+                                String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_TRADITIONAL_WATCH),
+                                String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_TIME_ONLY),
+                                String.valueOf(Global.Wearable.BATTERY_SAVER_MODE_CUSTOM)
+                        }));
+        VALIDATORS.put(
+                Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+                NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_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 821c372..bf8b933 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -34,7 +34,9 @@
 import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
 
 import android.provider.Settings.Secure;
+import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import java.util.Map;
 
@@ -288,5 +290,32 @@
         VALIDATORS.put(Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.DEVICE_STATE_ROTATION_LOCK, value -> {
+            if (TextUtils.isEmpty(value)) {
+                return true;
+            }
+            String[] intValues = value.split(":");
+            if (intValues.length % 2 != 0) {
+                return false;
+            }
+            InclusiveIntegerRangeValidator enumValidator =
+                    new InclusiveIntegerRangeValidator(
+                            Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED,
+                            Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+            ArraySet<String> keys = new ArraySet<>();
+            for (int i = 0; i < intValues.length - 1; ) {
+                String entryKey = intValues[i++];
+                String entryValue = intValues[i++];
+                if (!NON_NEGATIVE_INTEGER_VALIDATOR.validate(entryKey)
+                        || !enumValidator.validate(entryValue)) {
+                    return false;
+                }
+                // If the same device state key was specified more than once, this is invalid
+                if (!keys.add(entryKey)) {
+                    return false;
+                }
+            }
+            return true;
+        });
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9e7daf4..6bb125b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3588,7 +3588,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 204;
+            private static final int SETTINGS_VERSION = 205;
 
             private final int mUserId;
 
@@ -5215,8 +5215,8 @@
                         initGlobalSettingsDefaultValForWearLocked(
                                 Global.Wearable.RETAIL_MODE, Global.Wearable.RETAIL_MODE_CONSUMER);
                         initGlobalSettingsDefaultValForWearLocked(
-                                Global.Wearable.PLAY_STORE_AVAILABILITY,
-                                Global.Wearable.PLAY_STORE_AVAILABILITY_UNKNOWN);
+                                Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
+                                Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY_UNKNOWN);
                         initGlobalSettingsDefaultValForWearLocked(
                                 Global.Wearable.BUG_REPORT,
                                 "user".equals(Build.TYPE) // is user build?
@@ -5380,11 +5380,63 @@
                         initGlobalSettingsDefaultValForWearLocked(
                                 Settings.Global.Wearable.COMPANION_OS_VERSION,
                                 Settings.Global.Wearable.COMPANION_OS_VERSION_UNDEFINED);
+                        final boolean defaultBurnInProtectionEnabled =
+                                getContext()
+                                        .getResources()
+                                        .getBoolean(
+                                                com.android
+                                                        .internal
+                                                        .R
+                                                        .bool
+                                                        .config_enableBurnInProtection);
+                        final boolean forceBurnInProtection =
+                                SystemProperties.getBoolean("persist.debug.force_burn_in", false);
+                        initGlobalSettingsDefaultValForWearLocked(
+                                Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
+                                defaultBurnInProtectionEnabled || forceBurnInProtection);
 
                         // TODO(b/164398026): add necessary initialization logic for all entries.
                         currentVersion = 204;
                 }
 
+                if (currentVersion == 204) {
+                    // Version 204: Replace 'wifi' or 'cell' tiles with 'internet' if existed.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting currentValue = secureSettings.getSettingLocked(Secure.QS_TILES);
+                    if (!currentValue.isNull()) {
+                        String tileList = currentValue.getValue();
+                        String[] tileSplit = tileList.split(",");
+                        final ArrayList<String> tiles = new ArrayList<String>();
+                        boolean hasInternetTile = false;
+                        for (int i = 0; i < tileSplit.length; i++) {
+                            String tile = tileSplit[i].trim();
+                            if (tile.isEmpty()) continue;
+                            tiles.add(tile);
+                            if (tile.equals("internet")) hasInternetTile = true;
+                        }
+                        if (!hasInternetTile) {
+                            if (tiles.contains("wifi")) {
+                                // Replace the WiFi with Internet, and remove the Cell
+                                tiles.set(tiles.indexOf("wifi"), "internet");
+                                tiles.remove("cell");
+                            } else if (tiles.contains("cell")) {
+                                // Replace the Cell with Internet
+                                tiles.set(tiles.indexOf("cell"), "internet");
+                            }
+                        } else {
+                            tiles.remove("wifi");
+                            tiles.remove("cell");
+                        }
+                        secureSettings.insertSettingOverrideableByRestoreLocked(
+                                Secure.QS_TILES,
+                                TextUtils.join(",", tiles),
+                                null /* tag */,
+                                true /* makeDefault */,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 205;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f78d3b4..b210062 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -265,6 +265,9 @@
                     Settings.Global.ENABLE_DISKSTATS_LOGGING,
                     Settings.Global.ENABLE_EPHEMERAL_FEATURE,
                     Settings.Global.ENABLE_RESTRICTED_BUCKET,
+                    Settings.Global.ENABLE_TARE,
+                    Settings.Global.ENABLE_TARE_ALARM_MANAGER,
+                    Settings.Global.ENABLE_TARE_JOB_SCHEDULER,
                     Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
                     Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                     Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
@@ -473,6 +476,8 @@
                     Settings.Global.SYS_UIDCPUPOWER,
                     Settings.Global.SYS_TRACED,
                     Settings.Global.FPS_DEVISOR,
+                    Settings.Global.TARE_ALARM_MANAGER_CONSTANTS,
+                    Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS,
                     Settings.Global.TCP_DEFAULT_INIT_RWND,
                     Settings.Global.TETHER_DUN_APN,
                     Settings.Global.TETHER_DUN_REQUIRED,
@@ -592,6 +597,8 @@
                     Settings.Global.CACHED_APPS_FREEZER_ENABLED,
                     Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
                     Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
+                    Settings.Global.Wearable.BATTERY_SAVER_MODE,
+                    Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
                     Settings.Global.Wearable.HAS_PAY_TOKENS,
                     Settings.Global.Wearable.GMS_CHECKIN_TIMEOUT_MIN,
                     Settings.Global.Wearable.HOTWORD_DETECTION_ENABLED,
@@ -599,7 +606,7 @@
                     Settings.Global.Wearable.DEFAULT_VIBRATION,
                     Settings.Global.Wearable.OBTAIN_PAIRED_DEVICE_LOCATION,
                     Settings.Global.Wearable.RETAIL_MODE,
-                    Settings.Global.Wearable.PLAY_STORE_AVAILABILITY,
+                    Settings.Global.Wearable.PHONE_PLAY_STORE_AVAILABILITY,
                     Settings.Global.Wearable.BUG_REPORT,
                     Settings.Global.Wearable.SMART_ILLUMINATE_ENABLED,
                     Settings.Global.Wearable.CLOCKWORK_AUTO_TIME,
@@ -656,7 +663,9 @@
                     Settings.Global.Wearable.SETUP_LOCALE,
                     Settings.Global.Wearable.OEM_SETUP_VERSION,
                     Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
-                    Settings.Global.Wearable.UNGAZE_ENABLED);
+                    Settings.Global.Wearable.UNGAZE_ENABLED,
+                    Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
+                    Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
              newHashSet(
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index 989b53e..fc49f07 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -28,7 +28,7 @@
     <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైల్‌ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
+    <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైళ్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"మళ్లీ చూపవద్దు"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ రిపోర్ట్స్"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
new file mode 100644
index 0000000..68834bc
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+interface Flag<T> {
+    val id: Int
+    val default: T
+}
+
+data class BooleanFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Boolean = false
+) : Flag<Boolean>
+
+data class StringFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: String = ""
+) : Flag<String>
+
+data class IntFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Int = 0
+) : Flag<Int>
+
+data class LongFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Long = 0
+) : Flag<Long>
+
+data class FloatFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Float = 0f
+) : Flag<Float>
+
+data class DoubleFlag @JvmOverloads constructor(
+    override val id: Int,
+    override val default: Double = 0.0
+) : Flag<Double>
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
similarity index 82%
rename from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
rename to packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
index c7c2ad8..d5b9243 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.systemui.flags;
 
-parcelable InputConnectionCommand;
+/**
+ * List of {@link Flag} objects for use in SystemUI.
+ */
+public class Flags {
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java
new file mode 100644
index 0000000..ab17499
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+
+/**
+ * Plugin for loading flag values from an alternate source of truth.
+ */
+@ProvidesInterface(action = FlagReaderPlugin.ACTION, version = FlagReaderPlugin.VERSION)
+public interface FlagReaderPlugin extends Plugin {
+    int VERSION = 1;
+    String ACTION = "com.android.systemui.flags.FLAG_READER_PLUGIN";
+
+    /** Returns a boolean value for the given flag. */
+    default boolean isEnabled(int id, boolean def) {
+        return def;
+    }
+
+    /** Returns a string value for the given flag id. */
+    default String getValue(int id, String def) {
+        return def;
+    }
+
+    /** Returns a int value for the given flag. */
+    default int getValue(int id, int def) {
+        return def;
+    }
+
+    /** Returns a long value for the given flag. */
+    default long getValue(int id, long def) {
+        return def;
+    }
+
+    /** Returns a float value for the given flag. */
+    default float getValue(int id, float def) {
+        return def;
+    }
+
+    /** Returns a double value for the given flag. */
+    default double getValue(int id, double def) {
+        return def;
+    }
+
+    /** Add a listener to be alerted when any flag changes. */
+    default void addListener(Listener listener) {}
+
+    /** Remove a listener to be alerted when any flag changes. */
+    default void removeListener(Listener listener) {}
+
+    /** A simple listener to be alerted when a flag changes. */
+    interface Listener {
+        /** */
+        void onFlagChanged(int id);
+    }
+}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 28c6166..6016aaf 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -68,6 +68,16 @@
             lockScreenWeight="400"
         />
     </FrameLayout>
+    <FrameLayout
+        android:id="@+id/keyguard_smartspace_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/below_clock_padding_start"
+        android:paddingEnd="@dimen/below_clock_padding_end"
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/lockscreen_clock_view"
+        />
+    <!-- either keyguard_status_area or keyguard_smartspace_container is visible -->
     <include layout="@layout/keyguard_status_area"
         android:id="@+id/keyguard_status_area"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index ce63082..f613a19 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -27,49 +27,44 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:clipChildren="false"
-    android:clipToPadding="false"
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
+    android:clipChildren="false"
+    android:clipToPadding="false">
 
-    <FrameLayout
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/pattern_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-
-        <LinearLayout
-            android:id="@+id/pattern_container"
-            android:layout_height="wrap_content"
+        android:layout_height="0dp"
+        android:layout_marginBottom="8dp"
+        android:layout_weight="1"
+        android:layoutDirection="ltr">
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/pattern_top_guideline"
             android:layout_width="wrap_content"
-            android:orientation="vertical"
-            android:layout_gravity="center_horizontal|bottom"
-            android:clipChildren="false"
-            android:clipToPadding="false">
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintGuide_percent="0"
+            android:orientation="horizontal" />
 
-            <com.android.internal.widget.LockPatternView
-                android:id="@+id/lockPatternView"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                android:layout_marginEnd="8dip"
-                android:layout_marginBottom="4dip"
-                android:layout_marginStart="8dip"
-                android:layout_gravity="center_horizontal"
-                android:gravity="center"
-                android:clipChildren="false"
-                android:clipToPadding="false" />
+        <com.android.internal.widget.LockPatternView
+            android:id="@+id/lockPatternView"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"
+            androidprv:layout_constraintBottom_toBottomOf="parent"
+            androidprv:layout_constraintLeft_toLeftOf="parent"
+            androidprv:layout_constraintRight_toRightOf="parent"
+            androidprv:layout_constraintDimensionRatio="1.0"
+            androidprv:layout_constraintVertical_bias="1.0"
+            />
+    </androidx.constraintlayout.widget.ConstraintLayout>
 
-          <include layout="@layout/keyguard_eca"
-              android:id="@+id/keyguard_selector_fade_container"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:layout_gravity="bottom|center_horizontal"
-              android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-              android:gravity="center_horizontal" />
-        </LinearLayout>
-    </FrameLayout>
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+        android:gravity="center_horizontal" />
 
 </com.android.keyguard.KeyguardPatternView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index a22a56f..7c54b90 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -47,11 +47,11 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintBottom_toTopOf="@id/key1"
             androidprv:layout_constraintEnd_toEndOf="parent"
             androidprv:layout_constraintStart_toStartOf="parent"
 
             androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintBottom_toTopOf="@id/key1"
             androidprv:layout_constraintVertical_bias="1.0">
 
             <com.android.keyguard.PasswordTextView
@@ -65,6 +65,15 @@
                 androidprv:scaledTextSize="@integer/scaled_password_text_size" />
         </com.android.keyguard.AlphaOptimizedRelativeLayout>
 
+        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
+             updated in KeyguardPINView to reduce the height of the PIN pad. -->
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/pin_pad_top_guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintGuide_percent="0"
+            android:orientation="horizontal" />
+
         <androidx.constraintlayout.helper.widget.Flow
             android:id="@+id/flow1"
             android:layout_width="0dp"
@@ -78,16 +87,15 @@
             androidprv:flow_horizontalStyle="packed"
             androidprv:flow_maxElementsWrap="3"
 
+            androidprv:flow_verticalBias="1.0"
             androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
             androidprv:flow_verticalStyle="packed"
-            androidprv:flow_verticalBias="1.0"
 
             androidprv:flow_wrapMode="aligned"
-
-            androidprv:layout_constraintTop_toTopOf="parent"
             androidprv:layout_constraintBottom_toBottomOf="parent"
             androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent" />
+            androidprv:layout_constraintStart_toStartOf="parent"
+            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
 
         <com.android.keyguard.NumPadKey
             android:id="@+id/key1"
diff --git a/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
new file mode 100644
index 0000000..181ba07
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+-->
+<com.android.systemui.qs.QSFooterActionsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/qs_footer_actions_container"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:gravity="center_vertical">
+
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:id="@android:id/edit"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/qs_footer_action_button_size"
+        android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+        android:layout_weight="1"
+        android:background="@drawable/qs_footer_action_chip_background"
+        android:clickable="true"
+        android:clipToPadding="false"
+        android:contentDescription="@string/accessibility_quick_settings_edit"
+        android:focusable="true"
+        android:padding="@dimen/qs_footer_icon_padding"
+        android:src="@*android:drawable/ic_mode_edit"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <com.android.systemui.statusbar.phone.MultiUserSwitch
+        android:id="@+id/multi_user_switch"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/qs_footer_action_button_size"
+        android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+        android:layout_weight="1"
+        android:background="@drawable/qs_footer_action_chip_background"
+        android:focusable="true">
+
+        <ImageView
+            android:id="@+id/multi_user_avatar"
+            android:layout_width="@dimen/multi_user_avatar_expanded_size"
+            android:layout_height="@dimen/multi_user_avatar_expanded_size"
+            android:layout_gravity="center"
+            android:scaleType="centerInside" />
+    </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:id="@+id/pm_lite"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/qs_footer_action_button_size"
+        android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+        android:layout_weight="1"
+        android:background="@drawable/qs_footer_action_chip_background"
+        android:clickable="true"
+        android:clipToPadding="false"
+        android:focusable="true"
+        android:padding="@dimen/qs_footer_icon_padding"
+        android:src="@*android:drawable/ic_lock_power_off"
+        android:contentDescription="@string/accessibility_quick_settings_power_menu"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+        android:id="@+id/settings_button_container"
+        android:layout_width="0dp"
+        android:layout_height="@dimen/qs_footer_action_button_size"
+        android:background="@drawable/qs_footer_action_chip_background"
+        android:layout_weight="1"
+        android:clipChildren="false"
+        android:clipToPadding="false">
+
+        <com.android.systemui.statusbar.phone.SettingsButton
+            android:id="@+id/settings_button"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/qs_footer_action_button_size"
+            android:layout_gravity="center"
+            android:contentDescription="@string/accessibility_quick_settings_settings"
+            android:background="@drawable/qs_footer_action_chip_background_borderless"
+            android:padding="@dimen/qs_footer_icon_padding"
+            android:scaleType="centerInside"
+            android:src="@drawable/ic_settings"
+            android:tint="?android:attr/textColorPrimary" />
+
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:id="@+id/tuner_icon"
+            android:layout_width="8dp"
+            android:layout_height="8dp"
+            android:layout_gravity="center_horizontal|bottom"
+            android:layout_marginBottom="@dimen/qs_footer_icon_padding"
+            android:src="@drawable/tuner"
+            android:tint="?android:attr/textColorTertiary"
+            android:visibility="invisible" />
+
+    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+</com.android.systemui.qs.QSFooterActionsView>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 7e3c87b..a2ae5023 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -98,4 +98,10 @@
     <dimen name="below_clock_padding_start">32dp</dimen>
     <dimen name="below_clock_padding_end">16dp</dimen>
     <dimen name="below_clock_padding_start_icons">28dp</dimen>
+
+    <!-- Proportion of the screen height to use to set the maximum height of the bouncer to when
+         the device is in the DEVICE_POSTURE_HALF_OPENED posture, for the PIN/pattern entry. 0 will
+         allow it to use the whole screen space, 0.6 will allow it to use just under half of the
+         screen. -->
+    <item name="half_opened_bouncer_height_ratio" type="dimen" format="float">0.0</item>
 </resources>
diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res/anim/fp_to_unlock.xml
index a348208..a5f75b6 100644
--- a/packages/SystemUI/res/anim/fp_to_unlock.xml
+++ b/packages/SystemUI/res/anim/fp_to_unlock.xml
@@ -19,10 +19,10 @@
       <group android:name="_R_G">
         <group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
           <group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75">
-            <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
-            <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
-            <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
-            <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
+            <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
+            <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
+            <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
+            <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
           </group>
         </group>
         <group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res/anim/lock_to_unlock.xml
index ec51c01..76f7a05 100644
--- a/packages/SystemUI/res/anim/lock_to_unlock.xml
+++ b/packages/SystemUI/res/anim/lock_to_unlock.xml
@@ -21,7 +21,7 @@
           <group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
             <group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
               <group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375">
-                <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+                <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
               </group>
             </group>
           </group>
@@ -30,7 +30,7 @@
           <group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
             <group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
               <group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5">
-                <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
+                <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
               </group>
             </group>
           </group>
diff --git a/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
new file mode 100644
index 0000000..13133cb
--- /dev/null
+++ b/packages/SystemUI/res/anim/progress_indeterminate_horizontal_rect.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_rect2 in frameworks/base/core/res -->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="2000"
+        android:propertyXName="translateX"
+        android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0 "
+        android:interpolator="@interpolator/progress_indeterminate_horizontal_rect2_translatex_copy"
+        android:repeatCount="infinite" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/controls_icon.xml b/packages/SystemUI/res/drawable/controls_icon.xml
new file mode 100644
index 0000000..f1814a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M12,3L4,9v12h16L20,9l-8,-6zM18,19h-3v-6L9,13v6L6,19v-9l6,-4.5 6,4.5v9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/fingerprint_bg.xml b/packages/SystemUI/res/drawable/fingerprint_bg.xml
index 2b0ab6f..558ec08 100644
--- a/packages/SystemUI/res/drawable/fingerprint_bg.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_bg.xml
@@ -14,10 +14,11 @@
 -->
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="oval">
 
     <solid
-      android:color="?android:attr/colorBackground"/>
+      android:color="?androidprv:attr/colorSurface"/>
 
     <size
         android:width="64dp"
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
new file mode 100644
index 0000000..46023e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_unlock.xml
@@ -0,0 +1,42 @@
+<!--
+     Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
+    <group android:translateX="8.625" android:translateY="13.625">
+        <path
+            android:strokeColor="#FF000000"
+            android:strokeLineCap="round"
+            android:strokeLineJoin="round"
+            android:strokeWidth="2"
+            android:pathData="M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+    </group>
+    <group android:translateX="14" android:translateY="13.5">
+        <path
+            android:strokeColor="#FF000000"
+            android:strokeLineCap="round"
+            android:strokeLineJoin="round"
+            android:strokeWidth="2"
+            android:pathData="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
+    </group>
+    <group android:translateX="20" android:translateY="35.75">
+        <path
+            android:fillColor="#FF000000"
+            android:fillAlpha="1"
+            android:fillType="nonZero"
+            android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " />
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml
rename to packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
diff --git a/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 0000000..95209f8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Copy of progress_indeterminate_horizontal_material_trimmed in frameworks/base/core/res -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+    <target
+        android:name="rect_grp"
+        android:animation="@anim/progress_indeterminate_horizontal_rect" />
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 0000000..aec204f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+     draws the whole height of the progress bar instead having blank space above and below the
+     bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:height="10dp"
+        android:width="340dp"
+        android:viewportHeight="10"
+        android:viewportWidth="340" >
+    <group
+        android:name="progress_group"
+        android:translateX="180"
+        android:translateY="5" >
+        <path
+            android:name="background_track"
+            android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+            android:fillColor="?androidprv:attr/colorSurfaceVariant"/>
+        <group
+            android:name="rect_grp"
+            android:translateX="-197.60001"
+            android:scaleX="0.5" >
+            <path
+                android:name="rect"
+                android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+                android:fillColor="?androidprv:attr/colorAccentPrimaryVariant" />
+        </group>
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/communal_host_view.xml b/packages/SystemUI/res/layout/communal_host_view.xml
index d3698be..4406a46 100644
--- a/packages/SystemUI/res/layout/communal_host_view.xml
+++ b/packages/SystemUI/res/layout/communal_host_view.xml
@@ -22,5 +22,9 @@
     android:id="@+id/communal_host"
     android:orientation="vertical"
     systemui:layout_constraintEnd_toEndOf="parent"
+    systemui:layout_constraintStart_toStartOf="parent"
+    systemui:layout_constraintTop_toTopOf="parent"
+    systemui:layout_constraintBottom_toBottomOf="parent"
+    systemui:layout_constraintHeight_percent="@dimen/communal_source_height_percentage"
     android:layout_width="0dp"
     android:layout_height="0dp"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/idle_host_view.xml b/packages/SystemUI/res/layout/idle_host_view.xml
new file mode 100644
index 0000000..f407874
--- /dev/null
+++ b/packages/SystemUI/res/layout/idle_host_view.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+
+<com.android.systemui.idle.IdleHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/idle_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 7f22b71..f23085a 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -17,6 +17,7 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/internet_connectivity_dialog"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -28,7 +29,7 @@
         style="@style/Widget.SliceView.Panel"
         android:gravity="center_vertical|center_horizontal"
         android:layout_marginTop="24dp"
-        android:layout_marginBottom="24dp"
+        android:layout_marginBottom="16dp"
         android:layout_height="wrap_content"
         android:orientation="vertical">
 
@@ -46,7 +47,7 @@
             android:gravity="center_vertical|center_horizontal"
             android:layout_width="wrap_content"
             android:layout_height="20dp"
-            android:layout_marginTop="8dp"
+            android:layout_marginTop="4dp"
             android:ellipsize="end"
             android:maxLines="1"
             android:fontFamily="google-sans"
@@ -54,18 +55,20 @@
     </LinearLayout>
 
     <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="?android:attr/listDivider"/>
+        android:id="@+id/divider"
+        android:layout_gravity="center_vertical|center_horizontal"
+        android:layout_width="340dp"
+        android:layout_height="4dp"
+        android:background="?androidprv:attr/colorSurfaceVariant"/>
 
     <ProgressBar
         android:id="@+id/wifi_searching_progress"
         android:indeterminate="true"
-        android:layout_width="match_parent"
+        android:layout_width="340dp"
         android:layout_height="wrap_content"
-        android:minHeight="1dp"
-        android:maxHeight="1dp"
-        style="@*android:style/Widget.Material.ProgressBar.Horizontal"/>
+        android:layout_gravity="center_horizontal"
+        android:visibility="gone"
+        style="@style/TrimmedHorizontalProgressBar"/>
 
     <androidx.core.widget.NestedScrollView
         android:id="@+id/scroll_view"
@@ -91,12 +94,11 @@
                     android:background="?android:attr/selectableItemBackground"
                     android:layout_gravity="center_vertical|start"
                     android:orientation="horizontal"
-                    android:layout_marginRight="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginTop="4dp"
-                    android:layout_marginBottom="4dp"
-                    android:paddingStart="19dp"
-                    android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
+                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+                    android:layout_marginTop="16dp"
+                    android:paddingStart="22dp"
+                    android:paddingEnd="22dp">
 
                     <FrameLayout
                         android:layout_width="24dp"
@@ -105,6 +107,7 @@
                         android:layout_gravity="center_vertical|start">
                         <ImageView
                             android:id="@+id/signal_icon"
+                            android:autoMirrored="true"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:layout_gravity="center"/>
@@ -120,10 +123,11 @@
                         android:gravity="start|center_vertical">
                         <TextView
                             android:id="@+id/mobile_title"
-                            android:layout_marginLeft="17dp"
+                            android:textDirection="locale"
+                            android:layout_marginStart="16dp"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:layout_gravity="center_vertical"
+                            android:layout_gravity="center_vertical|start"
                             android:ellipsize="end"
                             android:maxLines="1"
                             android:textColor="?android:attr/textColorPrimary"
@@ -131,10 +135,11 @@
                             android:fontFamily="google-sans"/>
                         <TextView
                             android:id="@+id/mobile_summary"
-                            android:layout_marginLeft="17dp"
+                            android:textDirection="locale"
+                            android:layout_marginStart="16dp"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:layout_gravity="center_vertical"
+                            android:layout_gravity="center_vertical|start"
                             android:ellipsize="end"
                             android:maxLines="1"
                             android:textColor="?android:attr/textColorTertiary"
@@ -161,18 +166,16 @@
                 <LinearLayout
                     android:id="@+id/turn_on_wifi_layout"
                     android:layout_width="match_parent"
-                    android:layout_height="48dp"
+                    android:layout_height="72dp"
                     android:clickable="true"
                     android:focusable="true"
                     android:background="?android:attr/selectableItemBackground"
                     android:gravity="center"
                     android:orientation="horizontal"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginBottom="8dp"
-                    android:layout_marginRight="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
-                    android:paddingStart="@dimen/settingslib_switchbar_padding_left"
-                    android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
+                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+                    android:paddingStart="22dp"
+                    android:paddingEnd="22dp">
 
                     <FrameLayout
                         android:layout_weight="1"
@@ -182,6 +185,7 @@
                         android:layout_height="match_parent">
                         <TextView
                             android:text="@string/turn_on_wifi"
+                            android:textDirection="locale"
                             android:layout_width="wrap_content"
                             android:layout_height="match_parent"
                             android:gravity="start|center_vertical"
@@ -217,10 +221,10 @@
                     android:visibility="gone"
                     android:background="?android:attr/selectableItemBackground"
                     android:orientation="horizontal"
-                    android:layout_marginRight="@dimen/settingslib_switchbar_margin"
-                    android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
-                    android:paddingStart="@dimen/settingslib_switchbar_padding_left"
-                    android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+                    android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
+                    android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+                    android:paddingStart="22dp"
+                    android:paddingEnd="22dp">
 
                     <FrameLayout
                         android:layout_width="24dp"
@@ -244,10 +248,11 @@
                         android:gravity="start|center_vertical">
                         <TextView
                             android:id="@+id/wifi_connected_title"
+                            android:textDirection="locale"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:layout_gravity="center_vertical"
-                            android:layout_marginLeft="16dp"
+                            android:layout_gravity="center_vertical|start"
+                            android:layout_marginStart="16dp"
                             android:ellipsize="end"
                             android:maxLines="1"
                             android:textColor="?android:attr/textColorPrimary"
@@ -255,10 +260,11 @@
                             android:fontFamily="google-sans"/>
                         <TextView
                             android:id="@+id/wifi_connected_summary"
+                            android:textDirection="locale"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:layout_gravity="center_vertical"
-                            android:layout_marginLeft="16dp"
+                            android:layout_gravity="center_vertical|start"
+                            android:layout_marginStart="16dp"
                             android:ellipsize="end"
                             android:maxLines="1"
                             android:textColor="?android:attr/textColorTertiary"
@@ -269,7 +275,7 @@
                     <FrameLayout
                         android:layout_width="24dp"
                         android:layout_height="match_parent"
-                        android:layout_marginRight="5dp"
+                        android:layout_marginEnd="5dp"
                         android:clickable="false"
                         android:gravity="center">
                         <ImageView
@@ -301,8 +307,8 @@
                 android:background="?android:attr/selectableItemBackground"
                 android:gravity="center_vertical|center_horizontal"
                 android:orientation="horizontal"
-                android:paddingStart="@dimen/settingslib_switchbar_padding_left"
-                android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+                android:paddingStart="22dp"
+                android:paddingEnd="22dp">
 
                 <FrameLayout
                     android:layout_width="24dp"
@@ -323,9 +329,10 @@
                     android:clickable="false"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:layout_marginLeft="16dp">
+                    android:layout_marginStart="16dp">
                     <TextView
                         android:text="@string/see_all_networks"
+                        android:textDirection="locale"
                         android:layout_width="wrap_content"
                         android:layout_height="match_parent"
                         android:gravity="start|center_vertical"
@@ -353,7 +360,7 @@
                     android:id="@+id/done"
                     android:layout_width="60dp"
                     android:layout_height="30dp"
-                    android:layout_marginRight="24dp"
+                    android:layout_marginEnd="24dp"
                     android:layout_gravity="end"
                     android:background="@drawable/internet_dialog_footer_background"
                     android:textColor="?android:attr/textColorPrimary"
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
index cb51ab6..19b1ef9 100644
--- a/packages/SystemUI/res/layout/internet_list_item.xml
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -31,8 +31,8 @@
         android:focusable="true"
         android:background="?android:attr/selectableItemBackground"
         android:orientation="horizontal"
-        android:paddingStart="@dimen/settingslib_switchbar_padding_left"
-        android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+        android:paddingStart="22dp"
+        android:paddingEnd="22dp">
 
         <FrameLayout
             android:layout_width="24dp"
@@ -56,12 +56,13 @@
             android:layout_height="72dp">
             <TextView
                 android:id="@+id/wifi_title"
+                android:textDirection="locale"
                 android:layout_weight="1"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
-                android:layout_gravity="center_vertical"
+                android:layout_gravity="center_vertical|start"
                 android:gravity="start|center_vertical"
-                android:layout_marginLeft="16dp"
+                android:layout_marginStart="16dp"
                 android:ellipsize="end"
                 android:maxLines="1"
                 android:textColor="?android:attr/textColorPrimary"
@@ -69,12 +70,13 @@
                 android:fontFamily="google-sans"/>
             <TextView
                 android:id="@+id/wifi_summary"
+                android:textDirection="locale"
                 android:layout_weight="1"
                 android:layout_width="wrap_content"
                 android:layout_height="0dp"
-                android:layout_gravity="center_vertical"
+                android:layout_gravity="center_vertical|start"
                 android:gravity="start|center_vertical"
-                android:layout_marginLeft="16dp"
+                android:layout_marginStart="16dp"
                 android:ellipsize="end"
                 android:maxLines="1"
                 android:textColor="?android:attr/textColorSecondary"
@@ -85,7 +87,7 @@
         <FrameLayout
             android:layout_width="24dp"
             android:layout_height="match_parent"
-            android:layout_marginRight="@dimen/settingslib_switchbar_padding_right"
+            android:layout_marginEnd="@dimen/settingslib_switchbar_padding_right"
             android:clickable="false"
             android:gravity="center">
             <ImageView
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 9ce83a7..8dbd59d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -82,18 +82,32 @@
 
     <ImageView
         android:id="@+id/wallet_button"
-        android:layout_height="@dimen/keyguard_affordance_wallet_height"
-        android:layout_width="@dimen/keyguard_affordance_wallet_width"
+        android:layout_height="@dimen/keyguard_affordance_fixed_height"
+        android:layout_width="@dimen/keyguard_affordance_fixed_width"
         android:layout_gravity="bottom|end"
         android:scaleType="center"
         android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/ic_wallet_lockscreen"
-        android:background="@drawable/wallet_lockscreen_bg"
+        android:background="@drawable/keyguard_bottom_affordance_bg"
         android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
         android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
         android:contentDescription="@string/accessibility_wallet_button"
         android:visibility="gone" />
 
+    <ImageView
+        android:id="@+id/controls_button"
+        android:layout_height="@dimen/keyguard_affordance_fixed_height"
+        android:layout_width="@dimen/keyguard_affordance_fixed_width"
+        android:layout_gravity="bottom|start"
+        android:scaleType="center"
+        android:tint="?android:attr/textColorPrimary"
+        android:src="@drawable/controls_icon"
+        android:background="@drawable/keyguard_bottom_affordance_bg"
+        android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
+        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
+        android:contentDescription="@string/quick_controls_title"
+        android:visibility="gone" />
+
     <FrameLayout
         android:id="@+id/overlay_container"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 2789ed1..eb76382 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -30,6 +30,7 @@
         android:id="@+id/status_icon_area"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:paddingEnd="@dimen/system_icons_keyguard_padding_end"
         android:paddingTop="@dimen/status_bar_padding_top"
         android:layout_alignParentEnd="true"
         android:gravity="center_vertical|end" >
@@ -38,12 +39,10 @@
             android:layout_height="match_parent"
             android:layout_weight="1"
             android:layout_marginStart="@dimen/system_icons_super_container_margin_start"
-            android:gravity="center_vertical|end"
-            android:paddingEnd="@dimen/system_icons_keyguard_padding_end" >
+            android:gravity="center_vertical|end">
             <include layout="@layout/system_icons" />
         </FrameLayout>
 
-
         <ImageView android:id="@+id/multi_user_avatar"
             android:layout_width="@dimen/multi_user_avatar_keyguard_size"
             android:layout_height="@dimen/multi_user_avatar_keyguard_size"
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index c0d353b..075473a 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -185,7 +185,7 @@
         android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
         android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding"
         android:layout_marginTop="-22dp"
-        android:paddingBottom="0dp"
+        android:paddingBottom="2dp"
         android:splitTrack="false" />
 
     <!-- Song name -->
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 317dbc0..fe0b14a 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -68,93 +68,8 @@
 
         </LinearLayout>
 
-        <LinearLayout
-            android:id="@+id/qs_footer_actions_container"
-            android:layout_width="match_parent"
-            android:layout_height="48dp"
-            android:gravity="center_vertical">
+        <include layout="@layout/qs_footer_actions"/>
 
-            <com.android.systemui.statusbar.AlphaOptimizedImageView
-                android:id="@android:id/edit"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/qs_footer_action_button_size"
-                android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
-                android:layout_weight="1"
-                android:background="@drawable/qs_footer_action_chip_background"
-                android:clickable="true"
-                android:clipToPadding="false"
-                android:contentDescription="@string/accessibility_quick_settings_edit"
-                android:focusable="true"
-                android:padding="@dimen/qs_footer_icon_padding"
-                android:src="@*android:drawable/ic_mode_edit"
-                android:tint="?android:attr/textColorPrimary" />
-
-            <com.android.systemui.statusbar.phone.MultiUserSwitch
-                android:id="@+id/multi_user_switch"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/qs_footer_action_button_size"
-                android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
-                android:layout_weight="1"
-                android:background="@drawable/qs_footer_action_chip_background"
-                android:focusable="true">
-
-                <ImageView
-                    android:id="@+id/multi_user_avatar"
-                    android:layout_width="@dimen/multi_user_avatar_expanded_size"
-                    android:layout_height="@dimen/multi_user_avatar_expanded_size"
-                    android:layout_gravity="center"
-                    android:scaleType="centerInside" />
-            </com.android.systemui.statusbar.phone.MultiUserSwitch>
-
-            <com.android.systemui.statusbar.AlphaOptimizedImageView
-                android:id="@+id/pm_lite"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/qs_footer_action_button_size"
-                android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
-                android:layout_weight="1"
-                android:background="@drawable/qs_footer_action_chip_background"
-                android:clickable="true"
-                android:clipToPadding="false"
-                android:focusable="true"
-                android:padding="@dimen/qs_footer_icon_padding"
-                android:src="@*android:drawable/ic_lock_power_off"
-                android:contentDescription="@string/accessibility_quick_settings_power_menu"
-                android:tint="?android:attr/textColorPrimary" />
-
-            <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-                android:id="@+id/settings_button_container"
-                android:layout_width="0dp"
-                android:layout_height="@dimen/qs_footer_action_button_size"
-                android:background="@drawable/qs_footer_action_chip_background"
-                android:layout_weight="1"
-                android:clipChildren="false"
-                android:clipToPadding="false">
-
-                <com.android.systemui.statusbar.phone.SettingsButton
-                    android:id="@+id/settings_button"
-                    android:layout_width="match_parent"
-                    android:layout_height="@dimen/qs_footer_action_button_size"
-                    android:layout_gravity="center"
-                    android:contentDescription="@string/accessibility_quick_settings_settings"
-                    android:background="@drawable/qs_footer_action_chip_background_borderless"
-                    android:padding="@dimen/qs_footer_icon_padding"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_settings"
-                    android:tint="?android:attr/textColorPrimary" />
-
-                <com.android.systemui.statusbar.AlphaOptimizedImageView
-                    android:id="@+id/tuner_icon"
-                    android:layout_width="8dp"
-                    android:layout_height="8dp"
-                    android:layout_gravity="center_horizontal|bottom"
-                    android:layout_marginBottom="@dimen/qs_footer_icon_padding"
-                    android:src="@drawable/tuner"
-                    android:tint="?android:attr/textColorTertiary"
-                    android:visibility="invisible" />
-
-            </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
-        </LinearLayout>
     </LinearLayout>
 
 </com.android.systemui.qs.QSFooterView>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 1086c2b..1460cdf 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -97,7 +97,7 @@
             android:layout_height="match_parent"
             android:paddingEnd="@dimen/signal_cluster_battery_padding" />
 
-        <com.android.systemui.BatteryMeterView
+        <com.android.systemui.battery.BatteryMeterView
             android:id="@+id/batteryRemainingIcon"
             android:layout_height="match_parent"
             android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/split_shade_header.xml b/packages/SystemUI/res/layout/split_shade_header.xml
index 401dc19..f2c5b7b 100644
--- a/packages/SystemUI/res/layout/split_shade_header.xml
+++ b/packages/SystemUI/res/layout/split_shade_header.xml
@@ -78,7 +78,7 @@
                 android:layout_height="match_parent"
                 android:paddingEnd="@dimen/signal_cluster_battery_padding" />
 
-            <com.android.systemui.BatteryMeterView
+            <com.android.systemui.battery.BatteryMeterView
                 android:id="@+id/batteryRemainingIcon"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index da0010e..0c3c602 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,9 +55,23 @@
         android:id="@+id/lock_icon_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="48px"
-        android:layout_gravity="center"
-        android:scaleType="centerCrop"/>
+        android:layout_gravity="center">
+        <!-- Background protection -->
+        <ImageView
+            android:id="@+id/lock_icon_bg"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/fingerprint_bg"
+            android:visibility="invisible"/>
+
+        <ImageView
+            android:id="@+id/lock_icon"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:padding="@dimen/lock_icon_padding"
+            android:layout_gravity="center"
+            android:scaleType="centerCrop"/>
+    </com.android.keyguard.LockIconView>
 
     <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
         android:layout_width="match_parent"
@@ -73,7 +87,24 @@
             layout="@layout/keyguard_status_view"
             android:visibility="gone"/>
 
-        <include layout="@layout/dock_info_overlay" />
+        <include layout="@layout/idle_host_view"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:visibility="gone"/>
+
+        <FrameLayout
+            android:id="@+id/split_shade_smartspace_container"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:paddingStart="@dimen/notification_side_paddings"
+            android:paddingEnd="@dimen/notification_side_paddings"
+            systemui:layout_constraintStart_toStartOf="@id/qs_edge_guideline"
+            systemui:layout_constraintEnd_toEndOf="parent"
+            systemui:layout_constraintTop_toTopOf="parent"
+            android:visibility="gone">
+        </FrameLayout>
+
+        <include layout="@layout/dock_info_overlay"/>
 
         <FrameLayout
             android:id="@+id/qs_frame"
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 818d1d7..6d5c7d4 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -29,7 +29,7 @@
         android:gravity="center_vertical"
         android:orientation="horizontal"/>
 
-    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
+    <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery"
         android:layout_height="match_parent"
         android:layout_width="wrap_content"
         android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 8834ac0..a9eb27a 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -26,8 +26,7 @@
         android:id="@+id/udfps_keyguard_fp_bg"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@drawable/fingerprint_bg"
-        android:visibility="gone"/>
+        android:src="@drawable/fingerprint_bg"/>
 
     <!-- Fingerprint -->
     <!-- AOD dashed fingerprint icon with moving dashes -->
@@ -35,7 +34,7 @@
         android:id="@+id/udfps_aod_fp"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:padding="48px"
+        android:padding="@dimen/lock_icon_padding"
         android:layout_gravity="center"
         android:scaleType="centerCrop"
         app:lottie_autoPlay="false"
@@ -47,7 +46,7 @@
         android:id="@+id/udfps_lockscreen_fp"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:padding="48px"
+        android:padding="@dimen/lock_icon_padding"
         android:layout_gravity="center"
         android:scaleType="centerCrop"
         app:lottie_autoPlay="false"
diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json
index 3247fe7..3b273ff 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -164,7 +164,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -526,7 +526,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -829,7 +829,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1132,7 +1132,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1507,7 +1507,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1882,7 +1882,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -2257,7 +2257,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -2560,7 +2560,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
diff --git a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
index a25a475..a30a03a 100644
--- a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
+++ b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
@@ -1 +1 @@
-{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file
+{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b2274a6..394a6ce 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gebruik jou vingerafdruk om voort te gaan"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Kan nie vingerafdruk herken nie. Gebruik eerder skermslot."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Soek tans vir jou …"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gesig-ikoon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Versoenbaarheid-zoem se knoppie."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tik weer om oop te maak"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tik weer"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swiep op om oop te maak"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om oop te maak"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swiep op om weer te probeer"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkbesonderhede"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op \'n netwerk om te koppel"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index abb4ef9..c8184b6 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"የጣት አሻራን መለየት አልተቻለም። በምትኩ የማያ ገጽ መቆለፊያ ይጠቀሙ።"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"እርስዎን በመፈለግ ላይ…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"የፊት አዶ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"የተኳኋኝአጉላ አዝራር።"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ለመክፈት ዳግም መታ ያድርጉ"</string>
     <string name="tap_again" msgid="1315420114387908655">"እንደገና መታ ያድርጉ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ለመክፈት በጣት ወደ ላይ ጠረግ ያድርጉ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ለመክፈት ይጫኑ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"እንደገና ለመሞከር ወደ ላይ ይጥረጉ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"የአውታረ መረብ ዝርዝሮች"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ለመገናኘት አንድ አውታረ መረብ መታ ያድርጉ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"አውታረ መረቦችን በመፈለግ ላይ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ከአውታረ መረቡ ጋር መገናኘት አልተሳካም"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ad4402b..7160498 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"عليك استخدام بصمة الإصبع للمتابعة."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"يتعذّر التعرّف على بصمة الإصبع. عليك استخدام قفل الشاشة بدلاً من ذلك."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"جارٍ البحث عن وجهك…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"رمز الوجه"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"زر تكبير/تصغير للتوافق."</string>
@@ -460,6 +462,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"انقر مرة أخرى للفتح"</string>
     <string name="tap_again" msgid="1315420114387908655">"انقر مرة أخرى"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"يمكنك الفتح بالتمرير سريعًا لأعلى."</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"اضغط لفتح الجهاز."</string>
     <string name="keyguard_retry" msgid="886802522584053523">"مرِّر سريعًا للأعلى لإعادة المحاولة."</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏افتح قفل الشاشة لاستخدام تقنية NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
@@ -1193,6 +1196,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"تفاصيل الشبكة"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"انقر على إحدى الشبكات للاتصال بالإنترنت"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"جارٍ البحث عن شبكات…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"تعذّر الاتصال بالشبكة."</string>
     <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index f6c4aef..13f23f0 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -26,16 +26,10 @@
     <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"عبر <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
     <string name="tv_notification_panel_title" msgid="5311050946506276154">"الإشعارات"</string>
     <string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"ما من إشعارات"</string>
-    <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
-    <skip />
-    <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
-    <skip />
-    <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
-    <skip />
-    <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
-    <skip />
-    <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
-    <skip />
-    <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
-    <skip />
+    <string name="mic_recording_announcement" msgid="7587123608060316575">"جارٍ التسجيل بالميكرفون"</string>
+    <string name="camera_recording_announcement" msgid="7240177719403759112">"جارٍ التسجيل بالكاميرا"</string>
+    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"جارٍ التسجيل بالكاميرا والميكروفون"</string>
+    <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"توقف التسجيل بالميكرفون."</string>
+    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"توقف التسجيل بالكاميرا."</string>
+    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"توقف التسجيل بالكاميرا والميكروفون."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 17149a1..c60de55 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব নোৱাৰি। তাৰ সলনি স্ক্ৰীন লক ব্যৱহাৰ কৰক।"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"আপোনাৰ মুখমণ্ডল বিচাৰি আছে…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"মুখমণ্ডলৰ আইকন"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"উপযোগিতা অনুসৰি জুম কৰা বুটাম।"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"খুলিবলৈ পুনৰাই টিপক"</string>
     <string name="tap_again" msgid="1315420114387908655">"পুনৰ টিপক"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"খুলিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"খুলিবলৈ টিপক"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"পুনৰ চেষ্টা কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"ৱাই-ফাই"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"নেটৱৰ্কৰ সবিশেষ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"সংযোগ কৰিবলৈ এটা নেটৱৰ্কত টিপক"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটৱৰ্ক সন্ধান কৰি থকা হৈছে…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটৱৰ্কৰ সৈতে সংযোগ কৰিব পৰা নগ\'ল"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 6ceee80..733e2e6 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -26,16 +26,10 @@
     <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>ৰ জৰিয়তে"</string>
     <string name="tv_notification_panel_title" msgid="5311050946506276154">"জাননী"</string>
     <string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"কোনো জাননী নাই"</string>
-    <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
-    <skip />
-    <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
-    <skip />
-    <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
-    <skip />
-    <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
-    <skip />
-    <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
-    <skip />
-    <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
-    <skip />
+    <string name="mic_recording_announcement" msgid="7587123608060316575">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+    <string name="camera_recording_announcement" msgid="7240177719403759112">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰি আছে"</string>
+    <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"কেমেৰাটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
+    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"কেমেৰা আৰু মাইক্ৰ’ফ’নটোৱে ৰেক’ৰ্ড কৰাটো বন্ধ কৰিছে"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c1d520c..2ed55ce 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Davam etmək üçün barmaq izinizi istifadə edin"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Barmaq izini tanımaq olmur. Əvəzində ekran kilidindən istifadə edin."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Siz axtarılırsınız…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Üz işarəsi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Uyğunluq zoom düyməsi."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Açmaq üçün yenidən tıklayın"</string>
     <string name="tap_again" msgid="1315420114387908655">"Yenidən toxunun"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Açmaq üçün yuxarı sürüşdürün"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmaq üçün basın"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Yenidən cəhd etmək üçün yuxarı sürüşdürün"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Şəbəkə məlumatları"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Qoşulmaq üçün şəbəkəyə toxunun"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 0d6a635..b4df9f8 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prepoznavanje otiska prsta nije uspelo. Koristite zaključavanje ekrana umesto toga."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Dugme Zum kompatibilnosti."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da biste otvorili"</string>
     <string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite nagore da biste otvorili"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Prevucite nagore da biste probali ponovo"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index f810bbf..c5624ae 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Каб працягнуць, скарыстайце адбітак пальца"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не ўдалося распазнаць адбітак пальца. Разблакіруйце экран іншым спосабам."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ідзе пошук вашага твару…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок твару"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка сумяшчальнасці маштаба."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
     <string name="tap_again" msgid="1315420114387908655">"Націсніце яшчэ раз"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Каб адкрыць, прагарніце ўверх"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Націсніце, каб адкрыць"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Прагартайце ўверх, каб паўтарыць спробу"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Інфармацыя пра сетку"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Каб падключыцца, націсніце на сетку"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Выконваецца пошук сетак…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не ўдалося падключыцца да сеткі"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 8ac8dad..94d3a3f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Използвайте отпечатъка си, за да продължите"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Отпечатъкът не може да бъде разпознат. Вместо това използвайте опция за заключване на екрана."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Търсим ви…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона на лице"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Бутон за промяна на мащаба с цел съвместимост."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Докоснете отново, за да отворите"</string>
     <string name="tap_again" msgid="1315420114387908655">"Докоснете отново"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Прекарайте пръст нагоре, за да отключите"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натиснете за отваряне"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Плъзнете бързо нагоре, за да опитате отново"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Подробности за мрежата"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Докоснете мрежа, за да се свържете"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Търсят се мрежи…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Свързването с мрежата не бе успешно"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index eca5467..0174417 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"চালিয়ে যেতে আঙ্গুলের ছাপ ব্যবহার করুন"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"আঙ্গুলের ছাপ শনাক্ত করতে পারছি না। পরিবর্তে স্ক্রিন লক ব্যবহার করুন।"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"আপনার জন্য খোঁজা হচ্ছে…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ফেস আইকন"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"সামঞ্জস্যের জুম বোতাম৷"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"খোলার জন্য আবার আলতো চাপুন"</string>
     <string name="tap_again" msgid="1315420114387908655">"আবার ট্যাপ করুন"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"খোলার জন্য উপরে সোয়াইপ করুন"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"আনলক করার জন্য প্রেস করুন"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"আবার চেষ্টা করতে উপরের দিকে সোয়াইপ করুন"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"ওয়াই-ফাই"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"নেটওয়ার্কের বিবরণ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"কানেক্ট করতে একটি নেটওয়ার্কে ট্যাপ করুন"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 3ed40e7..ddf9cf0 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nije moguće prepoznati otisak prsta. Umjesto toga koristite zaključavanje ekrana."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da otvorite"</string>
     <string name="tap_again" msgid="1315420114387908655">"Ponovo dodirnite"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite da otvorite"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da otvorite"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Prevucite prema gore da pokušate ponovo"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
@@ -992,7 +995,7 @@
     <string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi mreže."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš operater"</string>
     <string name="touch_filtered_warning" msgid="8119511393338714836">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
-    <string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="slice_permission_text_1" msgid="6675965177075443714">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="slice_permission_text_2" msgid="6758906940360746983">"- Može poduzeti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="slice_permission_checkbox" msgid="4242888137592298523">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> prikazivanje isječaka iz svake aplikacije"</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da se povežete"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cceb9a8..adf9581 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Fes servir l\'empremta digital per continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No es pot reconèixer l\'empremta digital. Utilitza el bloqueig de pantalla."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"S\'està cercant la teva cara…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botó de zoom de compatibilitat."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Torna a tocar per obrir-la."</string>
     <string name="tap_again" msgid="1315420114387908655">"Torna a tocar"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Llisca cap amunt per obrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prem per obrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Llisca cap a dalt per tornar-ho a provar"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
@@ -576,7 +579,7 @@
     <string name="monitoring_description_network_logging" msgid="577305979174002252">"L\'administrador ha activat el registre de xarxa, que supervisa el trànsit del teu dispositiu.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
     <string name="monitoring_description_vpn" msgid="1685428000684586870">"Has donat permís a una aplicació per configurar una connexió VPN.\n\nAquesta aplicació pot supervisar el dispositiu i l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil de treball.\n\nL\'administrador pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador.\n\nA més, estàs connectat a una VPN, que també pot supervisar la teva activitat a la xarxa."</string>
-    <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o la teva mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
+    <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
     <string name="monitoring_description_app" msgid="376868879287922929">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalls de la xarxa"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una xarxa per connectar-te"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index adf156d..b061a34 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Pokračujte přiložením prstu"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Otisk prstu se nepodařilo rozpoznat. Použijte místo něj zámek obrazovky."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hledáme vás…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona obličeje"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Oznámení otevřete opětovným klepnutím"</string>
     <string name="tap_again" msgid="1315420114387908655">"Znovu klepněte"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Otevřete přejetím prstem nahoru"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stisknutím otevřete"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Přejetím nahoru to zkusíte znovu"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti sítě"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Klepněte na síť, ke které se chcete připojit"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2753f65..565c379 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Brug dit fingeraftryk for at fortsætte"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeraftrykket kan ikke genkendes. Brug skærmlåsen i stedet."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Forsøger at finde dig…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansigt"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knap for kompatibilitetszoom."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tryk igen for at åbne"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tryk igen"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Stryg opad for at åbne"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryk for at åbne"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Stryg opad for at prøve igen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Netværksoplysninger"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryk på et netværk for at oprette forbindelse"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c4fa1d7..e1c091c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Mithilfe deines Fingerabdrucks fortfahren"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingerabdruck wurde nicht erkannt. Verwende stattdessen die Displaysperre."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Wir suchen nach dir…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gesichtssymbol"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Schaltfläche für Kompatibilitätszoom"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
     <string name="tap_again" msgid="1315420114387908655">"Noch einmal tippen"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Zum Öffnen nach oben wischen"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Zum Öffnen klicken"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Zum Wiederholen nach oben wischen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
@@ -1082,7 +1085,7 @@
     <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string>
     <string name="controls_media_close_session" msgid="1193000643003066508">"Diese Mediensitzung ausblenden?"</string>
     <string name="controls_media_active_session" msgid="3146882316024153337">"Die Mediensitzung kann nicht ausgeblendet werden."</string>
-    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ablehnen"</string>
+    <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ausblenden"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>
     <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string>
     <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Netzwerkdetails"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tippe auf ein Netzwerk, um eine Verbindung herzustellen"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8cf0629..1f641b37 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Χρησιμοποιήστε δακτυλ. αποτύπωμα για να συνεχίσετε"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Δεν είναι δυνατή η αναγνώριση του δακτυλικού αποτυπώματος. Χρησιμοποιήστε εναλλακτικά το κλείδωμα οθόνης."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Αναζήτηση για εσάς…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Εικονίδιο προσώπου"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Κουμπί εστίασης συμβατότητας."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Πατήστε ξανά για να ανοίξετε"</string>
     <string name="tap_again" msgid="1315420114387908655">"Πατήστε ξανά"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Σύρετε προς τα επάνω για άνοιγμα"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Πατήστε για άνοιγμα"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Σύρετε προς τα πάνω για να δοκιμάσετε ξανά"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Λεπτομέρειες δικτύου"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Πατήστε ένα δίκτυο για να συνδεθείτε"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Αναζήτηση δικτύων…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Αποτυχία σύνδεσης στο δίκτυο"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9dd95c7..14673fb 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 03e596d..259cb17 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9dd95c7..14673fb 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9dd95c7..14673fb 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 1b9a302..e8f7e6b 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎Can’t recognize face. Use fingerprint instead.‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎Use your fingerprint to continue‎‏‎‎‏‎"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎Can’t recognize fingerprint. Use screen lock instead.‎‏‎‎‏‎"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎Looking for you…‎‏‎‎‏‎"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎Face icon‎‏‎‎‏‎"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎Compatibility zoom button.‎‏‎‎‏‎"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎Tap again to open‎‏‎‎‏‎"</string>
     <string name="tap_again" msgid="1315420114387908655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎Tap again‎‏‎‎‏‎"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎Swipe up to open‎‏‎‎‏‎"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎Press to open‎‏‎‎‏‎"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎Swipe up to try again‎‏‎‎‏‎"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎Unlock to use NFC‎‏‎‎‏‎"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎This device belongs to your organization‎‏‎‎‏‎"</string>
@@ -1169,6 +1172,7 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎Wi‑Fi‎‏‎‎‏‎"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎Network details‎‏‎‎‏‎"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎Tap a network to connect‎‏‎‎‏‎"</string>
+    <string name="unlock_to_view_networks" msgid="5072880496312015676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎Unlock to view networks‎‏‎‎‏‎"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎Searching for networks…‎‏‎‎‏‎"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎Failed to connect to network‎‏‎‎‏‎"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎See all‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f8eca13..7851017 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utiliza tu huella dactilar para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No se reconoce la huella dactilar. Utiliza el bloqueo de pantalla en su lugar."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Autenticando tu rostro…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícono de rostro"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidad"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Presiona de nuevo para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Presiona otra vez"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Presiona para abrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volver a intentarlo"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Presiona una red para conectarte a ella"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f2943ae..79dd8cd 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Usa tu huella digital para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No se reconoce la huella digital. Usa el bloqueo de pantalla."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Buscando tu cara…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icono de cara"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidad"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toca de nuevo"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pulsa para abrirlo"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volverlo a intentar"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una red para conectarte"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index a1ab2c4..9cfcbd5 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jätkamiseks kasutage sõrmejälge"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Sõrmejälge ei õnnestu tuvastada. Kasutage selle asemel ekraanilukku."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Otsitakse teid …"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Näoikoon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Sobivussuumi nupp."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Avamiseks puudutage uuesti"</string>
     <string name="tap_again" msgid="1315420114387908655">"Puudutage uuesti"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Pühkige avamiseks üles"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avamiseks vajutage"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Uuesti proovimiseks pühkige üles"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Võrgu üksikasjad"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Puudutage ühendamiseks võrku"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 177270a..340121c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ez da hauteman aurpegia. Erabili hatz-marka."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Aurrera egiteko, erabili hatz-marka"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Ez da hauteman hatz-marka. Erabili pantailaren blokeoa."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Zure bila…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Aurpegiaren ikonoa"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Zoom-bateragarritasunaren botoia."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
     <string name="tap_again" msgid="1315420114387908655">"Sakatu berriro"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Sakatu irekitzeko"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wifia"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Sarearen xehetasunak"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Sakatu sare bat hartara konektatzeko"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e06764d..d913f56 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"برای ادامه، از اثر انگشتتان استفاده کنید"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"اثر انگشت شناسایی نشد. درعوض از قفل صفحه استفاده کنید."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"درحال جستجوی شما…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"نماد چهره"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"دکمه بزرگ‌نمایی سازگار."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"دوباره ضربه بزنید تا باز شود"</string>
     <string name="tap_again" msgid="1315420114387908655">"دوباره ضربه بزنید"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"برای باز کردن، انگشتتان را تند به‌بالا بکشید"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"برای باز کردن فشار دهید"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"برای امتحان مجدد، انگشتتان را تند به‌بالا بکشید"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏برای استفاده از NFC، قفل را باز کنید"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"جزئیات شبکه"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"برای اتصال به شبکه روی آن ضربه بزنید"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 548d34c..66b0d4e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jatka sormenjäljen avulla"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Sormenjälkeä ei voi tunnistaa. Käytä sen sijaan näytön lukitusta."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Etsitään kasvoja…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Kasvokuvake"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Yhteensopivuuszoomaus-painike."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Avaa napauttamalla uudelleen"</string>
     <string name="tap_again" msgid="1315420114387908655">"Napauta uudelleen"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Avaa pyyhkäisemällä ylös"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avaa painamalla"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Yritä uudelleen pyyhkäisemällä ylös"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Verkon tiedot"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Muodosta yhteys napauttamalla verkkoa"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 7f942cc..a9fbb24 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilisez votre empreinte digitale pour continuer"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Empreinte digitale non reconnue. Utilisez plutôt le verrouillage de l\'écran."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Recherche de votre visage…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icône de visage"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Bouton \"Zoom de compatibilité\""</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Touchez à nouveau pour ouvrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toucher de nouveau"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la CCP"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Touchez un réseau pour vous y connecter"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index f540cfe..2f8b143 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilisez votre empreinte pour continuer"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Empreinte non reconnue. Utilisez le verrouillage de l\'écran."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Recherche de votre visage…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icône représentant un visage"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Bouton \"Zoom de compatibilité\""</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Appuyer à nouveau pour ouvrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Appuyer à nouveau"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Balayer vers le haut pour ouvrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Appuyez sur un réseau pour vous connecter"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 9b9c4f1..09a7d7b 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utiliza a túa impresión dixital para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Non se puido recoñecer a impresión dixital. Mellor usa o bloqueo de pantalla."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Buscándote…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona de cara"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidade"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Toca de novo para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toca de novo"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Pasa o dedo cara arriba para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Preme para abrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Pasa o dedo cara arriba para tentalo de novo"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles da rede"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca unha rede para conectarte a ela"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index eaaf776..2af29a3 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"આગળ વધવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ફિંગરપ્રિન્ટ ઓળખી શકતા નથી. તેને બદલે સ્ક્રીન લૉકનો ઉપયોગ કરો."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"તમારા માટે શોધી રહ્યાં છે..."</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ચહેરા આઇકન"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"સુસંગતતા ઝૂમ બટન."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ખોલવા માટે ફરીથી ટૅપ કરો"</string>
     <string name="tap_again" msgid="1315420114387908655">"ફરીથી ટૅપ કરો"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ખોલવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"અનલૉક કરવા માટે દબાવો"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ફરી પ્રયાસ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"વાઇ-ફાઇ"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"નેટવર્કની વિગતો"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"કનેક્ટ કરવા માટે નેટવર્ક પર ટૅપ કરો"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index c2c8ad6..e226503 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -26,16 +26,10 @@
     <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> મારફતે"</string>
     <string name="tv_notification_panel_title" msgid="5311050946506276154">"નોટિફિકેશન"</string>
     <string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"કોઈ નોટિફિકેશન નથી"</string>
-    <!-- no translation found for mic_recording_announcement (7587123608060316575) -->
-    <skip />
-    <!-- no translation found for camera_recording_announcement (7240177719403759112) -->
-    <skip />
-    <!-- no translation found for mic_and_camera_recording_announcement (8599231390508812667) -->
-    <skip />
-    <!-- no translation found for mic_stopped_recording_announcement (7301537004900721242) -->
-    <skip />
-    <!-- no translation found for camera_stopped_recording_announcement (8540496432367032801) -->
-    <skip />
-    <!-- no translation found for mic_camera_stopped_recording_announcement (8708524579599977412) -->
-    <skip />
+    <string name="mic_recording_announcement" msgid="7587123608060316575">"માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+    <string name="camera_recording_announcement" msgid="7240177719403759112">"કૅમેરાનું રેકોર્ડિંગ ચાલુ છે"</string>
+    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ ચાલુ છે"</string>
+    <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"કૅમેરાનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
+    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"કૅમેરા અને માઇક્રોફોનનું રેકોર્ડિંગ બંધ થઈ ગયું"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index c9636c2..cf3937f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"जारी रखने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फ़िंगरप्रिंट पहचाना नहीं जा सका. इसके बजाय, स्क्रीन लॉक इस्तेमाल करके देखें."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"आपको पहचान रहा है…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"चेहरे का आइकॉन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"संगतता ज़ूम बटन."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"खोलने के लिए फिर से टैप करें"</string>
     <string name="tap_again" msgid="1315420114387908655">"फिर से टैप करें"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"खोलने के लिए ऊपर स्वाइप करें"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलॉक करने के लिए दबाएं"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"फिर से कोशिश करने के लिए ऊपर की ओर स्वाइप करें"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"वाई-फ़ाई"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्क की जानकारी"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इंटरनेट से कनेक्ट करने के लिए, किसी नेटवर्क पर टैप करें"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क खोजे जा रहे हैं…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्क से कनेक्ट नहीं किया जा सका"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index 1135ecb..cc9a562 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -26,10 +26,10 @@
     <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> के ज़रिए"</string>
     <string name="tv_notification_panel_title" msgid="5311050946506276154">"सूचनाएं"</string>
     <string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"कोई सूचना नहीं है"</string>
-    <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफ़ोन आवाज़ रिकॉर्ड कर रहा है"</string>
-    <string name="camera_recording_announcement" msgid="7240177719403759112">"कैमरा वीडियो रिकॉर्ड कर रहा है"</string>
-    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कैमरा और माइक्रोफ़ोन वीडियो रिकॉर्ड कर रहे हैं"</string>
-    <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफ़ोन ने आवाज़ रिकॉर्ड करना बंद कर दिया है"</string>
-    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कैमरे ने वीडियो रिकॉर्ड करना बंद कर दिया है"</string>
-    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कैमरे और माइक्रोफ़ोन ने वीडियो रिकॉर्ड करना बंद कर दिया है"</string>
+    <string name="mic_recording_announcement" msgid="7587123608060316575">"माइक्रोफ़ोन रिकॉर्ड कर रहा है"</string>
+    <string name="camera_recording_announcement" msgid="7240177719403759112">"कैमरा रिकॉर्ड कर रहा है"</string>
+    <string name="mic_and_camera_recording_announcement" msgid="8599231390508812667">"कैमरा और माइक्रोफ़ोन रिकॉर्ड कर रहे हैं"</string>
+    <string name="mic_stopped_recording_announcement" msgid="7301537004900721242">"माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
+    <string name="camera_stopped_recording_announcement" msgid="8540496432367032801">"कैमरे ने रिकॉर्ड करना बंद कर दिया है"</string>
+    <string name="mic_camera_stopped_recording_announcement" msgid="8708524579599977412">"कैमरे और माइक्रोफ़ोन ने रिकॉर्ड करना बंद कर दिया है"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e341049..a118f8e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prepoznavanje otiska prsta nije uspjelo. Umjesto toga upotrebljavajte zaključavanje zaslona."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Gumb za kompatibilnost zumiranja."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite opet za otvaranje"</string>
     <string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Prijeđite prstom prema gore da biste otvorili"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Prijeđite prstom prema gore za ponovni pokušaj"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Pojedinosti o mreži"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 02eb298..2548ff1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"A folytatáshoz használja ujjlenyomatát"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Az ujjlenyomat nem ismerhető fel. Használja inkább a képernyőzárat."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Keresem az Ön arcát…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Arcikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kompatibilitási zoom gomb."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Koppintson ismét a megnyitáshoz"</string>
     <string name="tap_again" msgid="1315420114387908655">"Koppintson újra"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Csúsztasson felfelé a megnyitáshoz"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"A megnyitáshoz nyomja meg"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Az újrapróbálkozáshoz csúsztassa felfelé az ujját"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Hálózati információk"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"A kapcsolódáshoz koppintson a kívánt hálózatra"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index c3a3bb8..ab144d0 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Շարունակելու համար անհրաժեշտ է ձեր մատնահետքը"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Մատնահետքը չի հաջողվում ճանաչել։ Օգտագործեք էկրանի կողպումը։"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Դեմքի ճանաչում…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Դեմքի պատկերակ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Համատեղելիության խոշորացման կոճակը:"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Կրկին հպեք՝ բացելու համար"</string>
     <string name="tap_again" msgid="1315420114387908655">"Նորից հպեք"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Բացելու համար սահեցրեք վերև"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Սեղմեք՝ բացելու համար"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Սահեցրեք վերև՝ նորից փորձելու համար"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Ցանցի տվյալներ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Հպեք ցանցին՝ միանալու համար"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ցանցերի որոնում…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Չհաջողվեց միանալ ցանցին"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0444ee4..39726bf 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gunakan sidik jari untuk melanjutkan"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Tidak dapat mengenali sidik jari. Gunakan kunci layar."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Mencari wajah Anda…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikon wajah"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tombol perbesar/perkecil kompatibilitas."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ketuk lagi untuk membuka"</string>
     <string name="tap_again" msgid="1315420114387908655">"Ketuk lagi"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Geser ke atas untuk membuka"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk membuka"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Geser ke atas untuk mencoba lagi"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detail jaringan"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketuk jaringan untuk menghubungkan"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b57b93a..912b257e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Notaðu fingrafarið þitt til að halda áfram"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingrafar þekkist ekki. Notaðu skjálás í staðinn."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Leitar að þér ..."</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Andlitstákn"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Hnappur fyrir samhæfisaðdrátt."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ýttu aftur til að opna"</string>
     <string name="tap_again" msgid="1315420114387908655">"Ýttu aftur"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Strjúktu upp til að opna"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ýttu til að opna"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Strjúktu upp til að reyna aftur"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Upplýsingar um net"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ýttu á net til að tengjast"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 270c214..0ecb2db 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilizza la tua impronta per continuare"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Impossibile riconoscere l\'impronta. Usa il blocco schermo."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"In attesa del volto…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona volto"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Pulsante zoom compatibilità."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tocca ancora per aprire"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tocca di nuovo"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Scorri verso l\'alto per aprire"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Premi per aprire"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Scorri verso l\'alto per riprovare"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Dettagli rete"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tocca una rete per connetterti"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 899aca2..d1706ca 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"יש להשתמש בטביעת האצבע כדי להמשיך"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"לא ניתן לזהות את טביעת האצבע. יש להשתמש בנעילת המסך במקום."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"מתבצע חיפוש…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"סמל הפנים"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"לחצן מרחק מתצוגה של תאימות."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"יש להקיש שוב כדי לפתוח את ההתראה"</string>
     <string name="tap_again" msgid="1315420114387908655">"צריך להקיש פעם נוספת"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"צריך להחליק כדי לפתוח"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"יש להקיש כדי לפתוח"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"יש להחליק למעלה כדי לנסות שוב"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"פרטי הרשת"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"צריך להקיש על רשת כדי להתחבר"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e67841d..fa6107e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"続行するには指紋認証を使用してください"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"指紋を認識できません。代わりに画面ロックを使用してください。"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"顔を認証しています…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"顔アイコン"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"互換ズームボタン。"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"開くにはもう一度タップしてください"</string>
     <string name="tap_again" msgid="1315420114387908655">"もう一度タップしてください"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"開くには上にスワイプします"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"押すと開きます"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"上にスワイプしてもう一度お試しください"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
@@ -798,7 +801,7 @@
       <item quantity="other">%d分</item>
       <item quantity="one">%d分</item>
     </plurals>
-    <string name="battery_panel_title" msgid="5931157246673665963">"電池の使用状況"</string>
+    <string name="battery_panel_title" msgid="5931157246673665963">"バッテリーの使用状況"</string>
     <string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電中はバッテリー セーバーは利用できません"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"バッテリー セーバー"</string>
     <string name="battery_detail_switch_summary" msgid="3668748557848025990">"パフォーマンスとバックグラウンド データを制限します"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ネットワークの詳細"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ネットワークをタップして接続"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ネットワークを検索しています…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ネットワークに接続できませんでした"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 65813c6..d6aefbb 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"თითის ანაბეჭდის ამოცნობა ვერ ხერხდება. სანაცვლოდ, გამოიყენეთ ეკრანის დაბლოკვა."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"მიმდინარეობს თქვენი ძიება…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"სახის ხატულა"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"თავსებადი მასშტაბირების ღილაკი."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"შეეხეთ ისევ გასახსნელად"</string>
     <string name="tap_again" msgid="1315420114387908655">"შეეხეთ ხელახლა"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"გასახსნელად გადაფურცლეთ ზემოთ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"დააჭირეთ გასახსნელად"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ხელახლა საცდელად გადაფურცლეთ ზემოთ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ქსელის დეტალები"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"დასაკავშირებლად შეეხეთ ქსელს"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"მიმდინარეობს ქსელების ძიება…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ქსელთან დაკავშირება ვერ ხერხდება"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c902051..2dd97e7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Саусақ ізі танылмады. Орнына экран құлпын пайдаланыңыз."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Бет ізделуде…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Бет белгішесі"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Үйлесімділік ұлғайту түймесі."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ашу үшін қайта түртіңіз"</string>
     <string name="tap_again" msgid="1315420114387908655">"Қайта түртіңіз."</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Ашу үшін жоғары қарай сырғытыңыз."</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ашу үшін басыңыз."</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Әрекетті қайталау үшін жоғары сырғытыңыз."</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Желі деректері"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Желіге қосылу үшін оны түртіңіз."</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Маңайдағы желілер ізделуде…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Желіге қосылмады."</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 299187d..51ebaa7 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ប្រើ​ស្នាមម្រាមដៃ​របស់អ្នក ដើម្បីបន្ត"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"មិនអាចសម្គាល់​ស្នាមម្រាមដៃបានទេ។ សូមប្រើសោ​អេក្រង់ជំនួសវិញ។"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"កំពុងស្វែងរកអ្នក…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"រូប​ផ្ទៃមុខ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ប៉ះ​ម្ដង​ទៀត ដើម្បី​បើក"</string>
     <string name="tap_again" msgid="1315420114387908655">"ចុច​ម្ដងទៀត"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"អូសឡើងលើ​ដើម្បីបើក"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ចុច ដើម្បីបើក"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"អូសឡើងលើ ដើម្បី​ព្យាយាម​ម្ដងទៀត"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍​នេះគឺជា​កម្មសិទ្ធិរបស់​ស្ថាប័ន​អ្នក"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ព័ត៌មាន​លម្អិត​អំពីបណ្ដាញ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ចុចលើបណ្ដាញណាមួយ ដើម្បីភ្ជាប់"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"កំពុងស្វែងរកបណ្ដាញ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"មិន​អាច​ភ្ជាប់​បណ្ដាញ​បានទេ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index aadf662..7600f50 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಬದಲಾಗಿ ಪರದೆಲಾಕ್ ಬಳಸಿ."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ನಿಮಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ಮುಖದ ಐಕಾನ್‌"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ತೆರೆಯಲು ಮತ್ತೆ ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
     <string name="tap_again" msgid="1315420114387908655">"ಪುನಃ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ತೆರೆಯಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ತೆರೆಯಲು ಒತ್ತಿ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"ವೈ‑ಫೈ"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ನೆಟ್‌ವರ್ಕ್ ವಿವರಗಳು"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ಕನೆಕ್ಟ್ ಮಾಡಲು ಒಂದು ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e592f5a..598c206 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"계속하려면 지문을 사용하세요."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"지문을 인식할 수 없습니다. 화면 잠금을 대신 사용하세요."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"찾는 중..."</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"얼굴 아이콘"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"호환성 확대/축소 버튼입니다."</string>
@@ -353,7 +355,7 @@
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"위치 사용 중지"</string>
     <string name="quick_settings_camera_label" msgid="5612076679385269339">"카메라 액세스"</string>
     <string name="quick_settings_mic_label" msgid="8392773746295266375">"마이크 액세스"</string>
-    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"허용됨"</string>
+    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"사용 가능"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"차단됨"</string>
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"미디어 기기"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"다시 탭하여 열기"</string>
     <string name="tap_again" msgid="1315420114387908655">"다시 탭하세요."</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"위로 스와이프하여 열기"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"열려면 누르세요"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"위로 스와이프하여 다시 시도해 주세요"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"네트워크 세부정보"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"연결하려면 네트워크를 탭하세요"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"네트워크 검색 중…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"네트워크에 연결하지 못했습니다."</string>
     <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 38c0185..b583f24 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -48,8 +48,8 @@
   </string-array>
   <string-array name="tile_states_battery">
     <item msgid="6311253873330062961">"이용 불가"</item>
-    <item msgid="7838121007534579872">"꺼짐"</item>
-    <item msgid="1578872232501319194">"켜짐"</item>
+    <item msgid="7838121007534579872">"사용 안함"</item>
+    <item msgid="1578872232501319194">"사용"</item>
   </string-array>
   <string-array name="tile_states_dnd">
     <item msgid="467587075903158357">"이용 불가"</item>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index af1a0c0..58efcef 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Улантуу үчүн манжаңызды сканерге тийгизиңиз"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Манжа изи таанылбай жатат. Эрканды кулпулоо функциясын колдонуңуз."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Жүзүңүз изделүүдө…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Жүздүн сүрөтчөсү"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Масштабды сыйыштыруу баскычы."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ачуу үчүн кайра таптап коюңуз"</string>
     <string name="tap_again" msgid="1315420114387908655">"Кайра таптап коюңуз"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Ачуу үчүн өйдө сүрүңүз"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ачуу үчүн басыңыз"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Кайталоо үчүн экранды өйдө сүрүңүз"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
@@ -706,11 +709,11 @@
     <string name="tuner_full_importance_settings" msgid="1388025816553459059">"Эскертмелерди башкаруу каражаттары"</string>
     <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Күйүк"</string>
     <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Өчүк"</string>
-    <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрсөтүлөт \n- Билдирмелер толук экранда көрсөтүлөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрсөтүлөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
+    <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрүнөт \n- Билдирмелер толук экранда көрүнөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрүнөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
     <string name="notification_header_default_channel" msgid="225454696914642444">"Билдирмелер"</string>
     <string name="notification_channel_disabled" msgid="928065923928416337">"Мындан ары бул билдирмелер сизге көрүнбөйт"</string>
     <string name="notification_channel_minimized" msgid="6892672757877552959">"Бул билдирмелер кичирейтилет"</string>
-    <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрсөтүлөт"</string>
+    <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрүнөт"</string>
     <string name="notification_channel_unsilenced" msgid="94878840742161152">"Бул билдирмелер тууралуу кабарлап турабыз"</string>
     <string name="inline_blocking_helper" msgid="2891486013649543452">"Адатта мындай билдирмелерди өткөрүп жибересиз. \nАлар көрүнө берсинби?"</string>
     <string name="inline_done_button" msgid="6043094985588909584">"Бүттү"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Тармактын чоо-жайы"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Кайсы тармакка туташасыз?"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Тармактар изделүүдө…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Тармакка туташпай калды"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 6e0a9b3..32f3550 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ກະລຸນາໃຊ້ລາຍນິ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ບໍ່ສາມາດຈຳແນກລາຍນິ້ວມືໄດ້. ກະລຸນາໃຊ້ການລອກໜ້າຈໍແທນ."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ກຳລັງຊອກຫາທ່ານ…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ໄອຄອນໃບໜ້າ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ແຕະ​ອີກ​ຄັ້ງ​ເພື່ອ​ເປີດ"</string>
     <string name="tap_again" msgid="1315420114387908655">"ແຕະອີກເທື່ອໜຶ່ງ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ປັດຂຶ້ນເພື່ອເປີດ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ກົດເພື່ອເປີດ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ປັດຂຶ້ນເພື່ອລອງໃໝ່"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ລາຍລະອຽດເຄືອຂ່າຍ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ແຕະເຄືອຂ່າຍໃດໜຶ່ງເພື່ອເຊື່ອມຕໍ່"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ກຳລັງຊອກຫາເຄືອຂ່າຍ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ເຊື່ອມຕໍ່ເຄືອຂ່າຍບໍ່ສຳເລັດ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 01498b9..1380cf6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jei norite tęsti, naudokite kontrolinį kodą"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nepavyko atpažinti kontrolinio kodo. Naudokite ekrano užraktą."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ieškoma jūsų…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Veido piktograma"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Suderinamumo priartinimo mygtukas."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Palieskite dar kartą, kad atidarytumėte"</string>
     <string name="tap_again" msgid="1315420114387908655">"Palieskite dar kartą"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Perbraukite aukštyn, kad atidarytumėte"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Paspauskite, kad atidarytumėte"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Jei norite bandyti dar kartą, perbraukite aukštyn"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Išsami tinklo informacija"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Palieskite tinklą, kad prisijungtumėte"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c320321..d26c8b7 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Lai turpinātu, izmantojiet pirksta nospiedumu."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nevar atpazīt pirksta nospiedumu. Izmantojiet ekrāna bloķēšanu."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Notiek jūsu sejas meklēšana…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Sejas ikona"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Saderības tālummaiņas poga."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Pieskarieties vēlreiz, lai atvērtu"</string>
     <string name="tap_again" msgid="1315420114387908655">"Pieskarieties vēlreiz"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Velciet augšup, lai atvērtu"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nospiediet, lai atvērtu"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Velciet augšup, lai mēģinātu vēlreiz"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Dati par tīklu"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Pieskarieties tīklam, lai izveidotu savienojumu"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f2d40fe..673a45d 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Употребете го отпечатокот за да продолжите"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не се препознава отпечатокот. Користете заклучување екран."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ве бараме вас…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона за лице"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Копче за компатибилност на зум."</string>
@@ -243,7 +245,7 @@
     <skip />
     <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
     <skip />
-    <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено."</string>
+    <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено"</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Допрете повторно за да се отвори"</string>
     <string name="tap_again" msgid="1315420114387908655">"Допрете повторно"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Повлечете за да отворите"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притиснете за да отворите"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Повлечете нагоре за да се обидете повторно"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Детали за мрежата"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Допрете на мрежа за да се поврзете"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Се пребаруваат мрежи…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не успеа да се поврзе на мрежата"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 340dae0..e9e7068 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"തുടരുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിയാനാകുന്നില്ല. പകരം സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"നിങ്ങൾക്കായി തിരയുന്നു…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"മുഖത്തിന്റെ ഐക്കൺ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"തുറക്കുന്നതിന് വീണ്ടും ടാപ്പുചെയ്യുക"</string>
     <string name="tap_again" msgid="1315420114387908655">"വീണ്ടും ടാപ്പ് ചെയ്യുക"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"തുറക്കാൻ മുകളിലോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"തുറക്കാൻ അമർത്തുക"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"വീണ്ടും ശ്രമിക്കാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"വൈഫൈ"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"നെറ്റ്‌വർക്ക് വിശദാംശങ്ങൾ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"കണക്‌റ്റ് ചെയ്യാൻ ഒരു നെറ്റ്‌വർക്കിൽ ടാപ്പ് ചെയ്യുക"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"നെറ്റ്‌വർക്കുകൾ തിരയുന്നു…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"നെറ്റ്‌വർക്കിൽ കണക്റ്റ് ചെയ്യാനായില്ല"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 155f1a3..7ed4a9a 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Үргэлжлүүлэхийн тулд хурууныхаа хээг ашиглана уу"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Хурууны хээг таних боломжгүй. Оронд нь дэлгэцийн түгжээ ашиглана уу."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Таныг хайж байна…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Царайны дүрс тэмдэг"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Тохиромжтой өсгөх товч."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Нээхийн тулд дахин товшино уу"</string>
     <string name="tap_again" msgid="1315420114387908655">"Дaхин товшино уу"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Нээхийн тулд дээш шударна уу"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нээхийн тулд дарна уу"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Дахин оролдохын тулд дээш шударна уу"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Сүлжээний дэлгэрэнгүй мэдээлэл"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Холбогдохын тулд сүлжээг товшино уу"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 721b28f3..55e8805 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"पुढे सुरू ठेवण्‍यासाठी तुमची फिंगरप्रिंट वापरा"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फिंगरप्रिंट ओळखता आली नाही. त्याऐवजी स्क्रीन लॉक वापरा."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"तुमच्यासाठी शोधत आहे…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"चेहरा आयकन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"सुसंगतता झूम बटण."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string>
     <string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"उघडण्यासाठी दाबा"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"पुन्हा प्रयत्न करण्यासाठी वर स्‍वाइप करा"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"वाय-फाय"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कचे तपशील"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"कनेक्ट करण्यासाठी नेटवर्कवर टॅप करा"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्‍ट करता आले नाही"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 10d8b1e..eed8ebb 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gunakan cap jari anda untuk teruskan"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Tidak mengenali cap jari. Sebaliknya, gunakan kunci skrin."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Mencari anda…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikon wajah"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Butang zum keserasian."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ketik lagi untuk membuka"</string>
     <string name="tap_again" msgid="1315420114387908655">"Ketik sekali lagi"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Leret ke atas untuk buka"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk buka"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Leret ke atas untuk mencuba lagi"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Butiran rangkaian"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketik rangkaian untuk membuat sambungan"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9cc4ee2..29c8c8a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"လက်ဗွေကို မမှတ်မိပါ။ ဖန်သားပြင်လော့ခ်ချခြင်းကို အစားထိုးသုံးပါ။"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"သင့်ကို ရှာဖွေနေသည်…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"မျက်နှာသင်္ကေတ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"အံဝင်ခွင်ကျ ဇူးမ်ခလုတ်"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ဖွင့်ရန် ထပ်ပြီး ပုတ်ပါ"</string>
     <string name="tap_again" msgid="1315420114387908655">"ထပ်တို့ပါ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ဖွင့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ဖွင့်ရန် နှိပ်ပါ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ထပ်စမ်းကြည့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ကွန်ရက် အသေးစိတ်များ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ချိတ်ဆက်ရန် ကွန်ရက်ကို တို့ပါ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ကွန်ရက်များကို ရှာဖွေနေသည်…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ကွန်ရက်သို့ ချိတ်ဆက်၍မရပါ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e091c34..33bbd28 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Bruk fingeravtrykket for å fortsette"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeravtrykket gjenkjennes ikke. Bruk skjermlås i stedet."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ser etter deg …"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansiktikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Zoomknapp for kompatibilitet."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Trykk på nytt for å åpne"</string>
     <string name="tap_again" msgid="1315420114387908655">"Trykk igjen"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Sveip opp for å åpne"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Trykk for å åpne"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Sveip opp for å prøve igjen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Nettverksdetaljer"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trykk på et nettverk for å koble til"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b271ba6..f245cbb 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फिंगरप्रिन्ट पहिचान गर्न सकिएन। बरु स्क्रिन लक प्रयोग गर्नुहोस्।"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"तपाईंलाई खोज्दै…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"अनुहारको आइकन"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"मिलाउने जुम बटन।"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
     <string name="tap_again" msgid="1315420114387908655">"फेरि ट्याप गर्नुहोस्"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलक गर्न प्रेस गर्नुहोस्"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"फेरि प्रयास गर्न माथितिर स्वाइप गर्नुहोस्"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"यो डिभाइस तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कसम्बन्धी विवरण"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इन्टरनेट कनेक्ट गर्न कुनै नेटवर्कमा ट्याप गर्नुहोस्"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7331087..c748bff 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gebruik je vingerafdruk om door te gaan."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Vingerafdruk niet herkend. Gebruik in plaats daarvan de schermvergrendeling."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Jouw gezicht zoeken…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gezichtspictogram"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knop voor compatibiliteitszoom."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tik nog eens om te openen"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tik nog een keer"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om te openen"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkgegevens"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op een netwerk om verbinding te maken"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 6ff3814..6cb4412 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ଟିପଚିହ୍ନକୁ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ଆପଣଙ୍କୁ ଚିହ୍ନଟ କରୁଛି…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ମୁହଁ ଆଇକନ୍"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"କମ୍ପାଟିବିଲିଟୀ ଜୁମ୍ ବଟନ୍।"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ଖୋଲିବା ପାଇଁ ପୁଣି ଟାପ୍‍ କରନ୍ତୁ"</string>
     <string name="tap_again" msgid="1315420114387908655">"ପୁଣି ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ଖୋଲିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ଖୋଲିବାକୁ ଦବାନ୍ତୁ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ପୁଣି ଚେଷ୍ଟା କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"ୱାଇ-ଫାଇ"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ନେଟୱାର୍କ ବିବରଣୀ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ସଂଯୋଗ କରିବାକୁ ଏକ ନେଟୱାର୍କରେ ଟାପ୍ କରନ୍ତୁ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 542f341..110a3ee 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ।"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ਤੁਹਾਡੀ ਪਛਾਣ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ਅਨੁਰੂਪਤਾ ਜ਼ੂਮ ਬਟਨ।"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"ਖੋਲ੍ਹਣ ਲਈ ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
     <string name="tap_again" msgid="1315420114387908655">"ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"ਖੋਲ੍ਹਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਉੱਤੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"ਵਾਈ-ਫਾਈ"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ਨੈੱਟਵਰਕ ਵੇਰਵੇ"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ਕਨੈਕਟ ਕਰਨ ਲਈ ਕਿਸੇ ਨੈੱਟਵਰਕ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2d13f98..34484b7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Użyj odcisku palca, aby kontynuować"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nie rozpoznaję odcisku palca. Użyj blokady ekranu."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Szukam Cię…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona twarzy"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Przycisk powiększenia na potrzeby zgodności."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Kliknij ponownie, by otworzyć"</string>
     <string name="tap_again" msgid="1315420114387908655">"Kliknij jeszcze raz"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Przesuń w górę, by otworzyć"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Naciśnij, by otworzyć"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Przesuń w górę, by spróbować ponownie"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Szczegóły sieci"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Kliknij sieć, aby połączyć"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index cea977f..0d98daa2 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use sua impressão digital para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não foi possível reconhecer a impressão digital. Use o bloqueio de tela."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Procurando você…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão de zoom da compatibilidade."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 72bc64b..c8523f9 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilize a sua impressão digital para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não é possível reconhecer a impressão digital. Em alternativa, utilize o bloqueio de ecrã."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"À sua procura…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone de rosto"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão zoom de compatibilidade."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Deslize rapidamente para cima para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prima para abrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Deslize rapidamente para cima para tentar novamente."</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque numa rede para estabelecer ligação"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index cea977f..0d98daa2 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use sua impressão digital para continuar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não foi possível reconhecer a impressão digital. Use o bloqueio de tela."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Procurando você…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão de zoom da compatibilidade."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
     <string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 8a0edce..54933a5 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Folosiți amprenta pentru a continua"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Amprenta nu a fost recunoscută. Folosiți blocarea ecranului."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Vă căutăm…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Pictograma chip"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Buton zoom pentru compatibilitate."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Atingeți din nou pentru a deschide"</string>
     <string name="tap_again" msgid="1315420114387908655">"Atingeți din nou"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Glisați în sus pentru a deschide"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Apăsați pentru a deschide"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Glisați pentru a încerca din nou"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detalii despre rețea"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Atingeți o rețea pentru a vă conecta"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index cb852f6a..f99e52a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Чтобы продолжить, прикоснитесь пальцем к сканеру."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не удалось распознать отпечаток пальца. Используйте другой способ разблокировки экрана."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Поиск лица…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок лица"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка масштабирования (режим совместимости)"</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Нажмите ещё раз, чтобы открыть"</string>
     <string name="tap_again" msgid="1315420114387908655">"Нажмите ещё раз"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Проведите вверх, чтобы открыть"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нажмите, чтобы открыть."</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Чтобы повторить попытку, проведите вверх"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Сведения о сети"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Выберите сеть, чтобы подключиться"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index e8bc947..edaf8d5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ භාවිත කරන්න"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ඇඟිලි සලකුණ හඳුනා ගත නොහැකිය. ඒ වෙනුවට තිර අගුල භාවිත කරන්න."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ඔබව සොයමින්…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"මුහුණ නිරූපකය"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ගැළපෙන විශාලන බොත්තම."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string>
     <string name="tap_again" msgid="1315420114387908655">"නැවත තට්ටු කරන්න"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"විවෘත කිරීමට ස්වයිප් කරන්න"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"විවෘත කිරීමට ඔබන්න"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"නැවත උත්සාහ කිරීමට ඉහළට ස්වයිප් කරන්න"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"ජාල විස්තර"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"සම්බන්ධ වීමට ජාලයක් තට්ටු කරන්න"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ජාල සඳහා සොයමින්…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ජාලය වෙත සම්බන්ධ වීම අසාර්ථක විය"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4a646b3..cd5ce6f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Pokračujte nasnímaním odtlačku prsta"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Odtlačok prsta sa nedá rozpoznať. Použite radšej zámku obrazovky."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hľadáme vás…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona tváre"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Upozornenie otvoríte opätovným klepnutím"</string>
     <string name="tap_again" msgid="1315420114387908655">"Klepnite znova"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Otvorte potiahnutím prstom nahor"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stlačením otvoríte"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Potiahnutím nahor to skúste znova"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti siete"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ak sa chcete pripojiť, klepnite na sieť"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 627359a..1f717c1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Uporabite prstni odtis, če želite nadaljevati."</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prstnega odtisa ni mogoče prepoznati. Uporabite odklepanje s poverilnico."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Preverjanje vašega obraza …"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona obraza"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Gumb povečave za združljivost."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Znova se dotaknite, da odprete"</string>
     <string name="tap_again" msgid="1315420114387908655">"Znova se dotaknite možnosti"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Povlecite navzgor, da odprete"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite, če želite odpreti."</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Povlecite navzgor za vnovičen poskus"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Podatki o omrežju"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Za vzpostavitev povezave se dotaknite omrežja."</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index eb49af0..0d197cc 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Përdor gjurmën e gishtit për të vazhduar"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nuk mund ta dallojë gjurmën e gishtit. Përdor më mirë kyçjen e ekranit."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Po të kërkojmë…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona e fytyrës"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Butoni i zmadhimit të pajtueshmërisë."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Trokit përsëri për ta hapur"</string>
     <string name="tap_again" msgid="1315420114387908655">"Trokit sërish"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Shtyp për të hapur"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Detajet e rrjetit"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trokit te një rrjet për t\'u lidhur"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 91ccdc2..926bf2c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Наставите помоћу отиска прста"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Препознавање отиска прста није успело. Користите закључавање екрана уместо тога."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Тражимо вас…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона лица"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Дугме Зум компатибилности."</string>
@@ -454,6 +456,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Додирните поново да бисте отворили"</string>
     <string name="tap_again" msgid="1315420114387908655">"Додирните поново"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Превуците нагоре да бисте отворили"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притисните да бисте отворили"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Превуците нагоре да бисте пробали поново"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
@@ -1175,6 +1178,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Детаљи о мрежи"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Додирните мрежу да бисте се повезали"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Траже се мреже…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Повезивање са мрежом није успело"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 2ebdce2..56609c4 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Fortsätt med hjälp av ditt fingeravtryck"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeravtrycket kändes inte igen. Använd låsskärmen i stället."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Håller utkik efter dig …"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansiktsikon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knapp för kompatibilitetszoom."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Tryck igen för att öppna"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tryck igen"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Öppna genom att svepa uppåt"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryck för att öppna"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Svep uppåt om du vill försöka igen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Nätverksinformation"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryck på ett nätverk för att ansluta"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3eb941d..8fd84ce 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Tumia alama ya kidole chako ili uendelee"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Imeshindwa kutambua alama ya kidole. Tumia mbinu ya kufunga skrini badala yake."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Inakutafuta…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Aikoni ya uso"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kichupo cha kukuza kwa utangamanifu"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Gusa tena ili ufungue"</string>
     <string name="tap_again" msgid="1315420114387908655">"Gusa tena"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Telezesha kidole juu ili ufungue"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Bofya ili ufungue"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Telezesha kidole juu ili ujaribu tena"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Maelezo ya mtandao"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Gusa mtandao ili uunganishe"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 369e45c..ab159e1 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,10 +18,18 @@
     <!-- Max number of columns for quick controls area -->
     <integer name="controls_max_columns">2</integer>
 
-    <integer name="quick_settings_num_columns">2</integer>
+    <!-- The maximum number of rows in the QuickQSPanel -->
     <integer name="quick_qs_panel_max_rows">4</integer>
+
+    <!-- The maximum number of tiles in the QuickQSPanel -->
     <integer name="quick_qs_panel_max_tiles">8</integer>
 
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">true</bool>
+
+    <!-- The number of columns in the QuickSettings -->
+    <integer name="quick_settings_num_columns">2</integer>
+
+    <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+    <bool name="config_skinnyNotifsInLandscape">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 942cb2b..45b5afa 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -40,4 +40,8 @@
 
     <!-- How many lines to show in the security footer -->
     <integer name="qs_security_footer_maxLines">1</integer>
+
+    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
+    <bool name="allow_force_nav_bar_handle_opaque">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6a3cf34..c601783 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"தொடர்வதற்குக் கைரேகையைப் பயன்படுத்தவும்"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"கைரேகையை அடையாளம் காண முடியவில்லை. அதற்குப் பதிலாகத் திரைப்பூட்டைப் பயன்படுத்தவும்."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"உங்கள் முகத்தைத் தேடுகிறது…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"முக ஐகான்"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"பொருந்துமாறு அளவை மாற்றும் பட்டன்."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"திறக்க, மீண்டும் தட்டவும்"</string>
     <string name="tap_again" msgid="1315420114387908655">"மீண்டும் தட்டவும்"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"திறப்பதற்கு மேல் நோக்கி ஸ்வைப் செய்யவும்"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"திறப்பதற்கு அழுத்தவும்"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"மீண்டும் முயல மேல்நோக்கி ஸ்வைப் செய்யவும்"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"வைஃபை"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"நெட்வொர்க் விவரங்கள்"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"இணையத்துடன் இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 7828d4f..ef69f40 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -103,7 +103,7 @@
     <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నైనా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, ఆడియో ఉంటాయి."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ఆడియోను రికార్డ్ చేయి"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"పరికరం ఆడియో"</string>
-    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్‌లు, రింగ్‌టోన్‌ల వంటి ధ్వనులు"</string>
+    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్స్‌, రింగ్‌టోన్‌ల వంటి ధ్వనులు"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"మైక్రోఫోన్"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"పరికరం ఆడియో, మైక్రోఫోన్"</string>
     <string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభించు"</string>
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"వేలిముద్రను గుర్తించడం సాధ్యపడదు. బదులుగా స్క్రీన్ లాక్‌ను ఉపయోగించండి."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"మీ కోసం చూస్తోంది…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ముఖ చిహ్నం"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"అనుకూలత జూమ్ బటన్."</string>
@@ -445,13 +447,14 @@
     <string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
     <string name="zen_alarms_introduction" msgid="3987266042682300470">"అలారాలు నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
     <string name="zen_priority_customize_button" msgid="4119213187257195047">"అనుకూలీకరించు"</string>
-    <string name="zen_silence_introduction_voice" msgid="853573681302712348">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది. మీరు ఇప్పటికీ ఫోన్ కాల్‌లు చేయగలుగుతారు."</string>
+    <string name="zen_silence_introduction_voice" msgid="853573681302712348">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది. మీరు ఇప్పటికీ ఫోన్ కాల్స్‌ చేయగలుగుతారు."</string>
     <string name="zen_silence_introduction" msgid="6117517737057344014">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది."</string>
     <string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="7248696377626341060">"తక్కువ అత్యవసర నోటిఫికేషన్‌లు దిగువన"</string>
     <string name="notification_tap_again" msgid="4477318164947497249">"తెరవడానికి మళ్లీ నొక్కండి"</string>
     <string name="tap_again" msgid="1315420114387908655">"మళ్లీ ట్యాప్ చేయండి"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"తెరవడానికి, పైకి స్వైప్ చేయండి"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"తెరవడానికి నొక్కండి"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"మళ్ళీ ప్రయత్నించడానికి పైకి స్వైప్ చేయండి"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్‌లాక్ చేయండి"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
@@ -628,7 +631,7 @@
     <string name="stream_bluetooth_sco" msgid="6234562365528664331">"బ్లూటూత్"</string>
     <string name="stream_dtmf" msgid="7322536356554673067">"డ్యూయల్ మల్టీ టోన్ ఫ్రీక్వెన్సీ"</string>
     <string name="stream_accessibility" msgid="3873610336741987152">"యాక్సెసిబిలిటీ"</string>
-    <string name="ring_toggle_title" msgid="5973120187287633224">"కాల్‌లు"</string>
+    <string name="ring_toggle_title" msgid="5973120187287633224">"కాల్స్‌"</string>
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"రింగ్"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"వైబ్రేట్"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"మ్యూట్"</string>
@@ -644,7 +647,7 @@
     <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్‌మ్యూట్ చేయి"</string>
     <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
     <string name="volume_dialog_title" msgid="6502703403483577940">"%s వాల్యూమ్ నియంత్రణలు"</string>
-    <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"కాల్‌లు మరియు నోటిఫికేషన్‌లు రింగ్ అవుతాయి (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
+    <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు రింగ్ అవుతాయి (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
     <string name="output_title" msgid="3938776561655668350">"మీడియా అవుట్‌పుట్"</string>
     <string name="output_calls_title" msgid="7085583034267889109">"ఫోన్ కాల్ అవుట్‌పుట్"</string>
     <string name="output_none_found" msgid="5488087293120982770">"పరికరాలు ఏవీ కనుగొనబడలేదు"</string>
@@ -934,7 +937,7 @@
     <string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
     <string name="thermal_shutdown_title" msgid="2702966892682930264">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
     <string name="thermal_shutdown_message" msgid="6142269839066172984">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
-    <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n	• వనరు-ఆధారిత యాప్‌లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్‌లు) ఉపయోగించడం\n	• పెద్ద ఫైల్‌లను డౌన్‌లోడ్ లేదా అప్‌లోడ్ చేయడం\n	• అధిక ఉష్ణోగ్రతలలో మీ ఫోన్‌ని ఉపయోగించడం"</string>
+    <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n	• వనరు-ఆధారిత యాప్‌లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్‌లు) ఉపయోగించడం\n	• పెద్ద ఫైళ్లను డౌన్‌లోడ్ లేదా అప్‌లోడ్ చేయడం\n	• అధిక ఉష్ణోగ్రతలలో మీ ఫోన్‌ని ఉపయోగించడం"</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
@@ -957,7 +960,7 @@
     <string name="tuner_right" msgid="8247571132790812149">"కుడి"</string>
     <string name="tuner_menu" msgid="363690665924769420">"మెనూ"</string>
     <string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> అనురవర్తనం"</string>
-    <string name="notification_channel_alerts" msgid="3385787053375150046">"హెచ్చరికలు"</string>
+    <string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్‌లు"</string>
     <string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
     <string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్‌షాట్‌లు"</string>
     <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ సందేశాలు"</string>
@@ -1141,7 +1144,7 @@
     <string name="status_before_loading" msgid="1500477307859631381">"కంటెంట్ త్వరలో కనిపిస్తుంది"</string>
     <string name="missed_call" msgid="4228016077700161689">"మిస్డ్ కాల్"</string>
     <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
-    <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్‌లు, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
+    <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్స్‌, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
     <string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string>
     <string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string>
     <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్‌ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"నెట్‌వర్క్ వివరాలు"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"కనెక్ట్ చేయడానికి నెట్‌వర్క్‌ను ట్యాప్ చేయండి"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్‌వర్క్‌ల కోసం సెర్చ్ చేస్తోంది…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్‌వర్క్‌కు కనెక్ట్ చేయడం విఫలమైంది"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index a530ef4..e0e22df 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ไม่รู้จักลายนิ้วมือ ใช้การล็อกหน้าจอแทน"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"กำลังหาใบหน้าคุณ…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ไอคอนใบหน้า"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
@@ -353,7 +355,7 @@
     <string name="quick_settings_location_off_label" msgid="7923929131443915919">"ปิดตำแหน่ง"</string>
     <string name="quick_settings_camera_label" msgid="5612076679385269339">"สิทธิ์เข้าถึงกล้อง"</string>
     <string name="quick_settings_mic_label" msgid="8392773746295266375">"สิทธิ์เข้าถึงไมโครโฟน"</string>
-    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"มี"</string>
+    <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"พร้อมให้ใช้งาน"</string>
     <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ถูกบล็อก"</string>
     <string name="quick_settings_media_device_label" msgid="8034019242363789941">"อุปกรณ์สื่อ"</string>
     <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"แตะอีกครั้งเพื่อเปิด"</string>
     <string name="tap_again" msgid="1315420114387908655">"แตะอีกครั้ง"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"เลื่อนขึ้นเพื่อเปิด"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"กดเพื่อเปิด"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"เลื่อนขึ้นเพื่อลองอีกครั้ง"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"รายละเอียดเครือข่าย"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"แตะเครือข่ายเพื่อเชื่อมต่อ"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"กำลังค้นหาเครือข่าย…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"เชื่อมต่อเครือข่ายไม่สำเร็จ"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7bf902f..17b1149 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gamitin ang iyong fingerprint para magpatuloy"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Hindi makilala ang fingerprint. Gamitin na lang ang lock ng screen."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hinahanap ka…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Button ng zoom ng pagiging tugma."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"I-tap ulit upang buksan"</string>
     <string name="tap_again" msgid="1315420114387908655">"I-tap ulit"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Mag-swipe pataas para buksan"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pindutin para buksan"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Mag-swipe pataas para subukan ulit"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Mga detalye ng network"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Mag-tap ng network para kumonekta"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 2c51cc4..27914eb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Devam etmek için parmak izinizi kullanın"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Parmak izi tanınamadı. Bunun yerine ekran kilidini kullanın."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Yüzünüz tanınmaya çalışılıyor…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Yüz simgesi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Uyumluluk zum düğmesi."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Açmak için tekrar dokunun"</string>
     <string name="tap_again" msgid="1315420114387908655">"Tekrar dokunun"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Açmak için yukarı kaydırın"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmak için basın"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Tekrar denemek için yukarı kaydırın"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Kablosuz"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Ağ bilgileri"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Bağlanmak için bir ağa dokunun"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ae4772b..514b16c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Щоб продовжити, скористайтеся відбитком пальця"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Відбиток пальця не розпізнано. Використайте натомість дані для розблокування екрана."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Пошук обличчя…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок обличчя"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка масштабування сумісності."</string>
@@ -456,6 +458,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Торкніться знову, щоб відкрити"</string>
     <string name="tap_again" msgid="1315420114387908655">"Натисніть знову"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Проведіть пальцем угору, щоб відкрити"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натисніть, щоб відкрити"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
@@ -1181,6 +1184,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Деталі мережі"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Натисніть мережу, до якої потрібно підключитися"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Пошук мереж…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не вдалося підключитися до мережі"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 9cad711..a0d4a7b 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"جاری رکھنے کے لیے اپنا فنگر پرنٹ استعمال کریں"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"فنگر پرنٹ کی شناخت نہیں کی جا سکی۔ اس کے بجائے اسکرین لاک کا استعمال کریں۔"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"آپ کے لیے تلاش کیا جا رہا ہے…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"چہرے کا آئیکن"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"مطابقت پذیری زوم بٹن۔"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string>
     <string name="tap_again" msgid="1315420114387908655">"دوبارہ تھپتھپائیں"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"کھولنے کے لیے اوپر سوائپ کريں"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"کھولنے کے لیے دبائیں"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"دوبارہ کوشش کرنے کے لیے اوپر سوائپ کريں"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"‏NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"نیٹ ورک کی تفصیلات"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"منسلک کرنے کے لیے نیٹ ورک پر تھپتھپائیں"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 874af0f..743fce9 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Davom etish uchun barmoq izingizdan foydalaning"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Bu barmoq izi notanish. Ekran qulfi orqali urining."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Yuzingiz tekshirilmoqda…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Yuz belgisi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kattalashtirish tugmasi mosligi."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Ochish uchun yana bosing"</string>
     <string name="tap_again" msgid="1315420114387908655">"Yana bosing"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Ochish uchun tepaga suring"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ochish uchun bosing"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Qayta urinish uchun tepaga suring"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Tarmoq tafsilotlari"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ulanish uchun tarmoq ustiga bosing"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3506385f..abaffb8 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Hãy dùng vân tay để tiếp tục"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Không thể nhận dạng vân tay. Hãy dùng phương thức khóa màn hình."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Đang tìm kiếm bạn…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Biểu tượng khuôn mặt"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Nút thu phóng khả năng tương thích."</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Nhấn lại để mở"</string>
     <string name="tap_again" msgid="1315420114387908655">"Nhấn lại"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Vuốt lên để mở"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nhấn để mở"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Vuốt lên để thử lại"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Thông tin chi tiết về mạng"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Nhấn vào một mạng để kết nối"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
diff --git a/packages/SystemUI/res/values-w390dp/config.xml b/packages/SystemUI/res/values-w390dp/config.xml
new file mode 100644
index 0000000..222d848
--- /dev/null
+++ b/packages/SystemUI/res/values-w390dp/config.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <bool name="config_showBatteryEstimateQSBH">true</bool>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 62a4133..aed7910 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"使用指纹验证身份后才能继续"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"无法识别指纹。请改用屏幕锁定功能。"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在查找您的面孔…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"面孔图标"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"兼容性缩放按钮。"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"再次点按即可打开"</string>
     <string name="tap_again" msgid="1315420114387908655">"请再点按一次"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"向上滑动即可打开"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"按一下即可打开"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"向上滑动即可重试"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"网络详情"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"点按要连接的网络"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜索网络…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"未能连接到网络"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 42badd4..8d13a99 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"請使用您的指紋繼續"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"無法辨識指紋,請改用螢幕鎖定完成驗證。"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在搜尋您的臉孔…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"面孔圖示"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"相容性縮放按鈕。"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"再次輕按即可開啟"</string>
     <string name="tap_again" msgid="1315420114387908655">"再次輕按"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"請向上滑動以再試一次"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"網絡詳細資料"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕按網絡以連線"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網絡…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連接網絡"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ea5aac6..6e254d6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"使用指紋完成驗證才能繼續操作"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"無法辨識指紋,請改用螢幕鎖定完成驗證。"</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在尋找你的臉孔…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"臉孔圖示"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"相容性縮放按鈕。"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"再次輕觸即可開啟"</string>
     <string name="tap_again" msgid="1315420114387908655">"再輕觸一次"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"向上滑動即可重試"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"網路詳細資料"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕觸要連線的網路"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網路…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連上網路"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index de986d2..e52b6e7 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -184,6 +184,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
     <string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Sebenzisa izigxivizo zakho zeminwe ukuze uqhubeke"</string>
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Ayizazi izigxivizo zeminwe. Sebenzisa ukukhiya isikrini kunalokho."</string>
+    <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+    <skip />
     <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Kufunwa wena…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Isithonjana sobuso"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Inkinobho evumelekile yokusondeza"</string>
@@ -452,6 +454,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Thepha futhi ukuze uvule"</string>
     <string name="tap_again" msgid="1315420114387908655">"Thepha futhi"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Swayiphela phezulu ukuze uvule"</string>
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Chofoza ukuze uvule"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Swayiphela phezulu ukuze uzame futhi"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
@@ -1169,6 +1172,8 @@
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
     <string name="pref_title_network_details" msgid="1639455355897668883">"Imininingwane yenethiwekhi"</string>
     <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Thepha inethiwekhi ukuze uxhume"</string>
+    <!-- no translation found for unlock_to_view_networks (5072880496312015676) -->
+    <skip />
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bbbaf65..a4c1d94 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -291,6 +291,6 @@
     <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
     <!-- Material next track off color-->
     <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
-    <color name="connected_network_primary_color">#ff000000</color>
-    <color name="connected_network_tertiary_color">#808080</color>
+    <color name="connected_network_primary_color">#191C18</color>
+    <color name="connected_network_secondary_color">#41493D</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6dc7bc6..0aba7ce 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -110,7 +110,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
+        internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -549,6 +549,11 @@
         <item>@*android:string/status_bar_headset</item>
     </string-array>
 
+
+    <!-- Whether to show estimate in QS header. Default to false in case there's not enough
+     space -->
+    <bool name="config_showBatteryEstimateQSBH">false</bool>
+
     <!-- A path similar to frameworks/base/core/res/res/values/config.xml
       config_mainBuiltInDisplayCutout that describes a path larger than the exact path of a display
       cutout. If present as well as config_enableDisplayCutoutProtection is set to true, then
@@ -679,4 +684,23 @@
 
     <!-- Component name of communal source service -->
     <string name="config_communalSourceComponent" translatable="false">@null</string>
+
+    <!-- Whether idle mode should be enabled. When enabled, the lock screen will timeout to an idle
+         screen on inactivity. -->
+    <bool name="config_enableIdleMode">false</bool>
+
+    <!-- Timeout to idle mode duration in milliseconds. -->
+    <integer name="config_idleModeTimeout">10000</integer>
+
+    <!-- The maximum number of attempts to reconnect to the communal source target after failing
+         to connect -->
+    <integer name="config_communalSourceMaxReconnectAttempts">10</integer>
+
+    <!-- The initial amount of time (in milliseconds) before attempting to reconnect to a communal
+         source. This value is used as the base value in an exponential backoff in subsequent
+         attempts. -->
+    <integer name="config_communalSourceReconnectBaseDelay">1000</integer>
+
+    <!-- Flag to activate notification to contents feature -->
+    <bool name="config_notificationToContents">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2a9c54dd..aa45413 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -538,6 +538,9 @@
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
+    <!-- Padding for the lock icon on the keyguard. In pixels - should not scale with display size. -->
+    <dimen name="lock_icon_padding">48px</dimen>
+
     <!-- Height of the carrier/wifi name label -->
     <dimen name="carrier_label_height">24dp</dimen>
 
@@ -916,8 +919,8 @@
     <dimen name="keyguard_affordance_height">48dp</dimen>
     <dimen name="keyguard_affordance_width">48dp</dimen>
 
-    <dimen name="keyguard_affordance_wallet_height">48dp</dimen>
-    <dimen name="keyguard_affordance_wallet_width">48dp</dimen>
+    <dimen name="keyguard_affordance_fixed_height">48dp</dimen>
+    <dimen name="keyguard_affordance_fixed_width">48dp</dimen>
 
     <dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
     <dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
@@ -1293,7 +1296,7 @@
     <!-- Size of media cards in the QSPanel carousel -->
     <dimen name="qs_media_padding">16dp</dimen>
     <dimen name="qs_media_album_size_small">72dp</dimen>
-    <dimen name="qs_media_album_size">92dp</dimen>
+    <dimen name="qs_media_album_size">84dp</dimen>
     <dimen name="qs_media_album_radius">14dp</dimen>
     <dimen name="qs_media_album_device_padding">26dp</dimen>
     <dimen name="qs_media_info_margin">12dp</dimen>
@@ -1310,13 +1313,14 @@
     <dimen name="qs_footer_horizontal_margin">22dp</dimen>
     <dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
     <dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
-    <dimen name="qs_media_enabled_seekbar_vertical_padding">31dp</dimen>
-    <dimen name="qs_media_disabled_seekbar_vertical_padding">32dp</dimen>
+    <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
+    <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
 
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
-    <dimen name="qs_aa_media_rec_album_size_expanded">80dp</dimen>
+    <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
     <dimen name="qs_aa_media_rec_album_margin">8dp</dimen>
+    <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
     <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
 
     <!-- Window magnification -->
@@ -1622,4 +1626,9 @@
     <dimen name="settingslib_switch_track_height">24dp</dimen>
     <!-- Radius of switch track -->
     <dimen name="settingslib_switch_track_radius">31dp</dimen>
+
+    <!-- Height percentage of the parent container occupied by the communal view -->
+    <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
+
+    <dimen name="drag_and_drop_icon_size">70dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a8812bf..b9002c3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -438,6 +438,8 @@
     <string name="fingerprint_dialog_use_fingerprint">Use your fingerprint to continue</string>
     <!-- Message shown to ask the user to use screenlock to continue.[CHAR LIMIT=NONE] -->
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock">Can\u2019t recognize fingerprint. Use screen lock instead.</string>
+    <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
+    <string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
 
     <!-- Message shown when the system-provided face dialog is shown, asking for authentication [CHAR LIMIT=30] -->
     <string name="face_dialog_looking_for_face">Looking for you\u2026</string>
@@ -3012,6 +3014,8 @@
     <string name="pref_title_network_details" msgid="7329759534269363308">"Network details"</string>
     <!-- Provider Model: Panel subtitle for tapping a network to connect to internet. [CHAR LIMIT=60] -->
     <string name="tap_a_network_to_connect">Tap a network to connect</string>
+    <!-- Provider Model: Panel subtitle for unlocking screen to view networks. [CHAR LIMIT=60] -->
+    <string name="unlock_to_view_networks">Unlock to view networks</string>
     <!-- Provider Model: Wi-Fi settings. text displayed when Wi-Fi is on and network list is empty [CHAR LIMIT=50]-->
     <string name="wifi_empty_list_wifi_on">Searching for networks\u2026</string>
     <!-- Provider Model: Failure notification for connect -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 91d5d79..d254742 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -764,6 +764,8 @@
         <item name="android:windowBackground">@android:color/black</item>
         <item name="android:windowAnimationStyle">@null</item>
         <item name="android:statusBarColor">@android:color/black</item>
+        <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen -->
+        <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
         <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
     </style>
 
@@ -898,6 +900,8 @@
     <style name="Wallet.Theme" parent="@android:style/Theme.DeviceDefault">
       <item name="android:colorBackground">@android:color/system_neutral1_900</item>
       <item name="android:itemBackground">@android:color/system_neutral1_800</item>
+      <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen.  -->
+      <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
     </style>
 
     <style name="Animation.InternetDialog" parent="@android:style/Animation.InputMethod">
@@ -938,4 +942,13 @@
         <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
     </style>
 
+    <style name="TrimmedHorizontalProgressBar"
+           parent="android:Widget.Material.ProgressBar.Horizontal">
+        <item name="android:indeterminateDrawable">
+            @drawable/progress_indeterminate_horizontal_material_trimmed
+        </item>
+        <item name="android:minHeight">4dp</item>
+        <item name="android:maxHeight">4dp</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 9d706c5..0e284e6 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -93,7 +93,7 @@
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:layout_marginBottom="@dimen/qs_media_info_margin"
         app:layout_constrainedWidth="true"
-        android:layout_marginTop="@dimen/qs_media_info_spacing"
+        android:layout_marginTop="1dp"
         app:layout_constraintTop_toBottomOf="@id/header_title"
         app:layout_constraintStart_toStartOf="@id/header_title"
         app:layout_constraintEnd_toEndOf="parent"
@@ -104,7 +104,8 @@
         android:id="@+id/media_progress_bar"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        android:layout_marginTop="34dp"
+        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         />
@@ -124,7 +125,6 @@
         android:id="@+id/action0"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -139,7 +139,6 @@
         android:id="@+id/action1"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -153,7 +152,6 @@
         android:id="@+id/action2"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -167,7 +165,6 @@
         android:id="@+id/action3"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -181,7 +178,6 @@
         android:id="@+id/action4"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
index d8e132c..8a3d5ca 100644
--- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
@@ -43,7 +43,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -61,7 +61,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -79,7 +79,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
         app:layout_constraintStart_toEndOf="@id/media_cover2_container"
@@ -95,7 +95,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -113,7 +113,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -131,7 +131,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index 44271687..b82d896 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -80,8 +80,7 @@
     public static void begin(View v, @CujType int cujType, long timeout) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
         Configuration.Builder builder =
-                new Configuration.Builder(cujType)
-                        .setView(v)
+                Configuration.Builder.withView(cujType, v)
                         .setTimeout(timeout);
         InteractionJankMonitor.getInstance().begin(builder);
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 2407d21..68905f7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -68,6 +68,7 @@
     public final boolean isNotInRecents;
     public final Rect contentInsets;
     public final ActivityManager.RunningTaskInfo taskInfo;
+    public final boolean allowEnterPip;
     public final int rotationChange;
     public final int windowType;
 
@@ -88,6 +89,7 @@
         contentInsets = app.contentInsets;
         activityType = app.windowConfiguration.getActivityType();
         taskInfo = app.taskInfo;
+        allowEnterPip = app.allowEnterPip;
         rotationChange = 0;
 
         mStartLeash = app.startLeash;
@@ -214,6 +216,7 @@
             activityType = ACTIVITY_TYPE_UNDEFINED;
         }
         taskInfo = change.getTaskInfo();
+        allowEnterPip = change.getAllowEnterPip();
         mStartLeash = null;
         rotationChange = change.getEndRotation() - change.getStartRotation();
         windowType = INVALID_WINDOW_TYPE;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 9e456cf..27b6182 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -17,13 +17,13 @@
 package com.android.keyguard;
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
 
 import android.app.WallpaperManager;
 import android.text.TextUtils;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
@@ -93,8 +93,7 @@
 
     private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
 
-    // If set, will replace keyguard_status_area
-    private View mSmartspaceView;
+    private ViewGroup mSmartspaceContainer;
 
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private SmartspaceTransitionController mSmartspaceTransitionController;
@@ -139,6 +138,8 @@
 
         mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
         mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
+        mSmartspaceContainer = mView.findViewById(R.id.keyguard_smartspace_container);
+        mSmartspaceController.setKeyguardStatusContainer(mSmartspaceContainer);
 
         mClockViewController =
                 new AnimatableClockController(
@@ -170,35 +171,25 @@
         mView.updateColors(getGradientColors());
         updateAodIcons();
 
-        if (mSmartspaceController.isEnabled()) {
-            mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
+        if (mSmartspaceController.isSmartspaceEnabled()) {
+            // "Enabled" doesn't mean smartspace is displayed here - inside mSmartspaceContainer -
+            // it might be a part of another view when in split shade. But it means that it CAN be
+            // displayed here, so we want to hide keyguard_status_area and set views relations
+            // accordingly.
 
             View ksa = mView.findViewById(R.id.keyguard_status_area);
-            int ksaIndex = mView.indexOfChild(ksa);
+            // we show either keyguard_status_area or smartspace, so when smartspace can be visible,
+            // keyguard_status_area should be hidden
             ksa.setVisibility(View.GONE);
 
-            // Place smartspace view below normal clock...
-            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
-                    MATCH_PARENT, WRAP_CONTENT);
-            lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
-
-            mView.addView(mSmartspaceView, ksaIndex, lp);
-            int startPadding = getContext().getResources()
-                    .getDimensionPixelSize(R.dimen.below_clock_padding_start);
-            int endPadding = getContext().getResources()
-                    .getDimensionPixelSize(R.dimen.below_clock_padding_end);
-            mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
-
             updateClockLayout();
 
-            View nic = mView.findViewById(
-                    R.id.left_aligned_notification_icon_container);
-            lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
-            lp.addRule(RelativeLayout.BELOW, mSmartspaceView.getId());
+            View nic = mView.findViewById(R.id.left_aligned_notification_icon_container);
+            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
+            lp.addRule(RelativeLayout.BELOW, mSmartspaceContainer.getId());
             nic.setLayoutParams(lp);
-
-            mView.setSmartspaceView(mSmartspaceView);
-            mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
+            mView.setSmartspaceView(mSmartspaceContainer);
+            mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceContainer);
         }
     }
 
@@ -221,10 +212,7 @@
         // instance of this class. In order to fix this, we need to modify the plugin so that
         // (a) we get a new view each time and (b) we can properly clean up an old view by making
         // it unregister itself as a plugin listener.
-        if (mSmartspaceView != null) {
-            mView.removeView(mSmartspaceView);
-            mSmartspaceView = null;
-        }
+        mSmartspaceContainer.removeAllViews();
     }
 
     /**
@@ -237,7 +225,7 @@
     }
 
     private void updateClockLayout() {
-        if (mSmartspaceController.isEnabled()) {
+        if (mSmartspaceController.isSmartspaceEnabled()) {
             RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
                     MATCH_PARENT);
             lp.topMargin = getContext().getResources().getDimensionPixelSize(
@@ -302,8 +290,8 @@
         PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
                 scale, props, animate);
 
-        if (mSmartspaceView != null) {
-            PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
+        if (mSmartspaceContainer != null) {
+            PropertyAnimator.setProperty(mSmartspaceContainer, AnimatableProperty.TRANSLATION_X,
                     x, props, animate);
 
             // If we're unlocking with the SmartSpace shared element transition, let the controller
@@ -321,8 +309,8 @@
     public void setChildrenAlphaExcludingSmartspace(float alpha) {
         final Set<View> excludedViews = new HashSet<>();
 
-        if (mSmartspaceView != null) {
-            excludedViews.add(mSmartspaceView);
+        if (mSmartspaceContainer != null) {
+            excludedViews.add(mSmartspaceContainer);
         }
 
         setChildrenAlphaExcluding(alpha, excludedViews);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 97d3a5a..75425e1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -28,6 +28,7 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
@@ -166,6 +167,7 @@
         private final TelephonyManager mTelephonyManager;
         private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory;
         private final FalsingCollector mFalsingCollector;
+        private final DevicePostureController mDevicePostureController;
 
         @Inject
         public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -175,7 +177,8 @@
                 InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
                 @Main Resources resources, LiftToActivateListener liftToActivateListener,
                 TelephonyManager telephonyManager, FalsingCollector falsingCollector,
-                EmergencyButtonController.Factory emergencyButtonControllerFactory) {
+                EmergencyButtonController.Factory emergencyButtonControllerFactory,
+                DevicePostureController devicePostureController) {
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mLockPatternUtils = lockPatternUtils;
             mLatencyTracker = latencyTracker;
@@ -187,6 +190,7 @@
             mTelephonyManager = telephonyManager;
             mEmergencyButtonControllerFactory = emergencyButtonControllerFactory;
             mFalsingCollector = falsingCollector;
+            mDevicePostureController = devicePostureController;
         }
 
         /** Create a new {@link KeyguardInputViewController}. */
@@ -200,7 +204,8 @@
                 return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
-                        emergencyButtonController, mMessageAreaControllerFactory);
+                        emergencyButtonController, mMessageAreaControllerFactory,
+                        mDevicePostureController);
             } else if (keyguardInputView instanceof KeyguardPasswordView) {
                 return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -212,7 +217,8 @@
                 return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
-                        mLiftToActivateListener, emergencyButtonController, mFalsingCollector);
+                        mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
+                        mDevicePostureController);
             } else if (keyguardInputView instanceof KeyguardSimPinView) {
                 return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 82ade7a..1efda7e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,19 +16,23 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 
 /**
  * Displays a PIN pad for unlocking.
@@ -38,9 +42,10 @@
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
-    private ViewGroup mContainer;
+    private ConstraintLayout mContainer;
     private int mDisappearYTranslation;
     private View[][] mViews;
+    @DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
 
     public KeyguardPINView(Context context) {
         this(context, null);
@@ -67,6 +72,11 @@
         updateMargins();
     }
 
+    void onDevicePostureChanged(@DevicePostureInt int posture) {
+        mLastDevicePosture = posture;
+        updateMargins();
+    }
+
     @Override
     protected void resetState() {
     }
@@ -109,6 +119,16 @@
                 key.setLayoutParams(lp);
             }
         }
+
+        // Update the guideline based on the device posture...
+        float halfOpenPercentage =
+                mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
+
+        ConstraintSet cs = new ConstraintSet();
+        cs.clone(mContainer);
+        cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
+                mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+        cs.applyTo(mContainer);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 90c1e40..3a3d308 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -209,6 +209,11 @@
                     @Override
                     public void onCancelled(
                             @Nullable WindowInsetsAnimationController controller) {
+                        // It is possible to be denied control of ime insets, which means onReady
+                        // is never called. We still need to notify the runnables in order to
+                        // complete the bouncer disappearing
+                        runOnFinishImeAnimationRunnable();
+                        finishRunnable.run();
                     }
                 });
         return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 98e7fb4..a35aedf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,6 +15,8 @@
  */
 package com.android.keyguard;
 
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.SystemClock;
@@ -22,16 +24,19 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
+
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.widget.LockPatternView;
 import com.android.settingslib.animation.AppearAnimationCreator;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 
 public class KeyguardPatternView extends KeyguardInputView
         implements AppearAnimationCreator<LockPatternView.CellState> {
@@ -68,7 +73,7 @@
 
     KeyguardMessageArea mSecurityMessageDisplay;
     private View mEcaView;
-    private ViewGroup mContainer;
+    private ConstraintLayout mContainer;
 
     public KeyguardPatternView(Context context) {
         this(context, null);
@@ -90,6 +95,18 @@
                 mContext, android.R.interpolator.fast_out_linear_in));
     }
 
+    void onDevicePostureChanged(@DevicePostureInt int posture) {
+        // Update the guideline based on the device posture...
+        float halfOpenPercentage =
+                mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
+
+        ConstraintSet cs = new ConstraintSet();
+        cs.clone(mContainer);
+        cs.setGuidelinePercent(R.id.pin_pad_top_guideline, posture == DEVICE_POSTURE_HALF_OPENED
+                ? halfOpenPercentage : 0.0f);
+        cs.applyTo(mContainer);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index d5be7ba..94e07b7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -38,6 +38,7 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingClassifier;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.statusbar.policy.DevicePostureController;
 
 import java.util.List;
 
@@ -56,6 +57,9 @@
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
     private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
+    private final DevicePostureController mPostureController;
+    private final DevicePostureController.Callback mPostureCallback =
+            posture -> mView.onDevicePostureChanged(posture);
 
     private KeyguardMessageAreaController mMessageAreaController;
     private LockPatternView mLockPatternView;
@@ -192,7 +196,8 @@
             LatencyTracker latencyTracker,
             FalsingCollector falsingCollector,
             EmergencyButtonController emergencyButtonController,
-            KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
+            KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+            DevicePostureController postureController) {
         super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
@@ -203,6 +208,7 @@
         KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
         mMessageAreaController = mMessageAreaControllerFactory.create(kma);
         mLockPatternView = mView.findViewById(R.id.lockPatternView);
+        mPostureController = postureController;
     }
 
     @Override
@@ -235,6 +241,7 @@
                 getKeyguardSecurityCallback().onCancelClicked();
             });
         }
+        mPostureController.addCallback(mPostureCallback);
     }
 
     @Override
@@ -247,6 +254,7 @@
         if (cancelBtn != null) {
             cancelBtn.setOnClickListener(null);
         }
+        mPostureController.removeCallback(mPostureCallback);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 262bed3..9f4585f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -23,10 +23,14 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.statusbar.policy.DevicePostureController;
 
 public class KeyguardPinViewController
         extends KeyguardPinBasedInputViewController<KeyguardPINView> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final DevicePostureController mPostureController;
+    private final DevicePostureController.Callback mPostureCallback = posture ->
+            mView.onDevicePostureChanged(posture);
 
     protected KeyguardPinViewController(KeyguardPINView view,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -35,11 +39,13 @@
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
             EmergencyButtonController emergencyButtonController,
-            FalsingCollector falsingCollector) {
+            FalsingCollector falsingCollector,
+            DevicePostureController postureController) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 emergencyButtonController, falsingCollector);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mPostureController = postureController;
     }
 
     @Override
@@ -53,6 +59,14 @@
                 getKeyguardSecurityCallback().onCancelClicked();
             });
         }
+
+        mPostureController.addCallback(mPostureCallback);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        super.onViewDetached();
+        mPostureController.removeCallback(mPostureCallback);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5ef7143..6908409 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -103,10 +103,10 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.telephony.TelephonyListenerManager;
@@ -149,7 +149,7 @@
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
     private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_SPEW = false;
-    private static final int LOW_BATTERY_THRESHOLD = 20;
+    private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
 
     private static final String ACTION_FACE_UNLOCK_STARTED
             = "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -347,13 +347,16 @@
     private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
     private static final int HAL_ERROR_RETRY_MAX = 20;
 
-    private final Runnable mCancelNotReceived = new Runnable() {
-        @Override
-        public void run() {
-            Log.w(TAG, "Cancel not received, transitioning to STOPPED");
-            mFingerprintRunningState = mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-            updateBiometricListeningState();
-        }
+    private final Runnable mFpCancelNotReceived = () -> {
+        Log.e(TAG, "Fp cancellation not received, transitioning to STOPPED");
+        mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+        updateFingerprintListeningState();
+    };
+
+    private final Runnable mFaceCancelNotReceived = () -> {
+        Log.e(TAG, "Face cancellation not received, transitioning to STOPPED");
+        mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+        updateFaceListeningState();
     };
 
     private final Handler mHandler;
@@ -791,19 +794,19 @@
 
     private void handleFingerprintError(int msgId, String errString) {
         Assert.isMainThread();
-        if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks(
-                mCancelNotReceived)) {
-            mHandler.removeCallbacks(mCancelNotReceived);
+        if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
+            mHandler.removeCallbacks(mFpCancelNotReceived);
         }
 
+        // Error is always the end of authentication lifecycle.
+        mFingerprintCancelSignal = null;
+
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
                 && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
             updateFingerprintListeningState();
         } else {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
-            mFingerprintCancelSignal = null;
-            mFaceCancelSignal = null;
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
@@ -834,7 +837,18 @@
     private void handleFingerprintLockoutReset() {
         mFingerprintLockedOut = false;
         mFingerprintLockedOutPermanent = false;
-        updateFingerprintListeningState();
+
+        if (isUdfpsEnrolled()) {
+            // TODO(b/194825098): update the reset signal(s)
+            // A successful unlock will trigger a lockout reset, but there is no guarantee
+            // that the events will arrive in a particular order. Add a delay here in case
+            // an unlock is in progress. In this is a normal unlock the extra delay won't
+            // be noticeable.
+            mHandler.postDelayed(this::updateFingerprintListeningState,
+                    FINGERPRINT_LOCKOUT_RESET_DELAY_MS);
+        } else {
+            updateFingerprintListeningState();
+        }
     }
 
     private void setFingerprintRunningState(int fingerprintRunningState) {
@@ -894,6 +908,7 @@
 
     private void handleFaceAuthFailed() {
         Assert.isMainThread();
+        mFaceCancelSignal = null;
         setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -972,10 +987,13 @@
     private void handleFaceError(int msgId, String errString) {
         Assert.isMainThread();
         if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString);
-        if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) {
-            mHandler.removeCallbacks(mCancelNotReceived);
+        if (mHandler.hasCallbacks(mFaceCancelNotReceived)) {
+            mHandler.removeCallbacks(mFaceCancelNotReceived);
         }
 
+        // Error is always the end of authentication lifecycle
+        mFaceCancelSignal = null;
+
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -2357,6 +2375,14 @@
     }
 
     private void startListeningForFingerprint() {
+        final int userId = getCurrentUser();
+        final boolean unlockPossible = isUnlockWithFingerprintPossible(userId);
+        if (mFingerprintCancelSignal != null) {
+            Log.e(TAG, "Cancellation signal is not null, high chance of bug in fp auth lifecycle"
+                    + " management. FP state: " + mFingerprintRunningState
+                    + ", unlockPossible: " + unlockPossible);
+        }
+
         if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING) {
             setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
             return;
@@ -2366,11 +2392,8 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
-        int userId = getCurrentUser();
-        if (isUnlockWithFingerprintPossible(userId)) {
-            if (mFingerprintCancelSignal != null) {
-                mFingerprintCancelSignal.cancel();
-            }
+
+        if (unlockPossible) {
             mFingerprintCancelSignal = new CancellationSignal();
 
             if (isEncryptedOrLockdown(userId)) {
@@ -2386,6 +2409,14 @@
     }
 
     private void startListeningForFace() {
+        final int userId = getCurrentUser();
+        final boolean unlockPossible = isUnlockWithFacePossible(userId);
+        if (mFaceCancelSignal != null) {
+            Log.e(TAG, "Cancellation signal is not null, high chance of bug in face auth lifecycle"
+                    + " management. Face state: " + mFaceRunningState
+                    + ", unlockPossible: " + unlockPossible);
+        }
+
         if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
             setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
             return;
@@ -2394,11 +2425,8 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFace(): " + mFaceRunningState);
-        int userId = getCurrentUser();
-        if (isUnlockWithFacePossible(userId)) {
-            if (mFaceCancelSignal != null) {
-                mFaceCancelSignal.cancel();
-            }
+
+        if (unlockPossible) {
             mFaceCancelSignal = new CancellationSignal();
 
             // This would need to be updated for multi-sensor devices
@@ -2450,9 +2478,8 @@
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
                 mFingerprintCancelSignal = null;
-                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
-                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
-                }
+                mHandler.removeCallbacks(mFpCancelNotReceived);
+                mHandler.postDelayed(mFpCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
             }
             setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
         }
@@ -2467,9 +2494,8 @@
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
                 mFaceCancelSignal = null;
-                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
-                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
-                }
+                mHandler.removeCallbacks(mFaceCancelNotReceived);
+                mHandler.postDelayed(mFaceCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
             }
             setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
         }
@@ -2831,6 +2857,11 @@
             mSecureCameraLaunched = false;
         }
 
+        if (mKeyguardBypassController != null) {
+            // LS visibility has changed, so reset deviceEntryIntent
+            mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index c1d448d..622419a8 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -17,15 +17,21 @@
 package com.android.keyguard;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.PointF;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import androidx.annotation.NonNull;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.R;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -33,16 +39,47 @@
 /**
  * A view positioned under the notification shade.
  */
-public class LockIconView extends ImageView implements Dumpable {
+public class LockIconView extends FrameLayout implements Dumpable {
     @NonNull private final RectF mSensorRect;
     @NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
     private int mRadius;
 
+    private ImageView mLockIcon;
+    private ImageView mUnlockBgView;
+
+    private int mLockIconColor;
+
     public LockIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mSensorRect = new RectF();
     }
 
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        mLockIcon = findViewById(R.id.lock_icon);
+        mUnlockBgView = findViewById(R.id.lock_icon_bg);
+    }
+
+    void updateColorAndBackgroundVisibility(boolean useBackground) {
+        if (useBackground) {
+            mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
+                    android.R.attr.textColorPrimary);
+            mUnlockBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
+            mUnlockBgView.setVisibility(View.VISIBLE);
+        } else {
+            mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
+                    R.attr.wallpaperTextColorAccent);
+            mUnlockBgView.setVisibility(View.GONE);
+        }
+
+        mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor));
+    }
+
+    void setImageDrawable(Drawable drawable) {
+        mLockIcon.setImageDrawable(drawable);
+    }
+
     void setCenterLocation(@NonNull PointF center, int radius) {
         mLockIconCenter = center;
         mRadius = radius;
@@ -56,9 +93,12 @@
 
         setX(mSensorRect.left);
         setY(mSensorRect.top);
-        setLayoutParams(new FrameLayout.LayoutParams(
+
+        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
                 (int) (mSensorRect.right - mSensorRect.left),
-                (int) (mSensorRect.bottom - mSensorRect.top)));
+                (int) (mSensorRect.bottom - mSensorRect.top));
+        lp.gravity = Gravity.CENTER;
+        setLayoutParams(lp);
     }
 
     @Override
@@ -70,7 +110,6 @@
         return mLockIconCenter.y - mRadius;
     }
 
-
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 9c8582fa..509ac8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -43,7 +43,6 @@
 import androidx.annotation.Nullable;
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
@@ -97,8 +96,8 @@
     @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon;
     @NonNull private final Drawable mLockIcon;
     @NonNull private final Drawable mUnlockIcon;
-    @NonNull private final CharSequence mUnlockedLabel;
-    @NonNull private final CharSequence mLockedLabel;
+    @NonNull private CharSequence mUnlockedLabel;
+    @NonNull private CharSequence mLockedLabel;
     @Nullable private final Vibrator mVibrator;
 
     private boolean mIsDozing;
@@ -111,7 +110,7 @@
     private boolean mUserUnlockedWithBiometric;
     private Runnable mCancelDelayedUpdateVisibilityRunnable;
 
-    private boolean mHasUdfps;
+    private boolean mUdfpsSupported;
     private float mHeightPixels;
     private float mWidthPixels;
     private int mBottomPadding; // in pixels
@@ -152,9 +151,8 @@
 
         final Context context = view.getContext();
         mUnlockIcon = mView.getContext().getResources().getDrawable(
-            R.anim.lock_to_unlock,
+            R.drawable.ic_unlock,
             mView.getContext().getTheme());
-        ((AnimatedVectorDrawable) mUnlockIcon).start();
         mLockIcon = mView.getContext().getResources().getDrawable(
                 R.anim.lock_to_unlock,
                 mView.getContext().getTheme());
@@ -177,7 +175,7 @@
     protected void onViewAttached() {
         // we check this here instead of onInit since the FingerprintManager + FaceManager may not
         // have started up yet onInit
-        mHasUdfps = mAuthController.getUdfpsSensorLocation() != null;
+        mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
 
         updateConfiguration();
         updateKeyguardShowing();
@@ -307,12 +305,7 @@
     }
 
     private void updateColors() {
-        final int color = Utils.getColorAttrDefaultColor(mView.getContext(),
-                R.attr.wallpaperTextColorAccent);
-        mFpToUnlockIcon.setTint(color);
-        mLockToUnlockIcon.setTint(color);
-        mLockIcon.setTint(color);
-        mUnlockIcon.setTint(color);
+        mView.updateColorAndBackgroundVisibility(mUdfpsSupported);
     }
 
     private void updateConfiguration() {
@@ -321,11 +314,17 @@
         mHeightPixels = metrics.heightPixels;
         mBottomPadding = mView.getContext().getResources().getDimensionPixelSize(
                 R.dimen.lock_icon_margin_bottom);
+
+        mUnlockedLabel = mView.getContext().getResources().getString(
+                R.string.accessibility_unlock_button);
+        mLockedLabel = mView.getContext()
+                .getResources().getString(R.string.accessibility_lock_icon);
+
         updateLockIconLocation();
     }
 
     private void updateLockIconLocation() {
-        if (mHasUdfps) {
+        if (mUdfpsSupported) {
             FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
             mView.setCenterLocation(new PointF(props.sensorLocationX, props.sensorLocationY),
                     props.sensorRadius);
@@ -467,6 +466,7 @@
         @Override
         public void onConfigChanged(Configuration newConfig) {
             updateConfiguration();
+            updateColors();
         }
     };
 
@@ -514,7 +514,15 @@
                     if (!wasClickableOnDownEvent()) {
                         return false;
                     }
+                    onAffordanceClick();
+                    return true;
+                }
 
+                public boolean onFling(MotionEvent e1, MotionEvent e2,
+                        float velocityX, float velocityY) {
+                    if (!wasClickableOnDownEvent()) {
+                        return false;
+                    }
                     onAffordanceClick();
                     return true;
                 }
@@ -560,7 +568,7 @@
     }
 
     private boolean isClickable() {
-        return mUdfpsEnrolled || mShowUnlockIcon;
+        return mUdfpsSupported || mShowUnlockIcon;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index a672523..fc14b6a 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -18,6 +18,7 @@
 
 import com.android.keyguard.CarrierText;
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
 
 import dagger.Module;
@@ -31,4 +32,11 @@
     static CarrierText getCarrierText(KeyguardStatusBarView view) {
         return view.findViewById(R.id.keyguard_carrier_text);
     }
+
+    /** */
+    @Provides
+    @KeyguardStatusBarViewScope
+    static BatteryMeterView getBatteryMeterView(KeyguardStatusBarView view) {
+        return view.findViewById(R.id.battery);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d258eca..48c5e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -47,6 +47,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -73,7 +74,6 @@
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index e9c5653..f653088 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -797,8 +797,8 @@
     }
 
     static boolean shouldDrawCutout(Context context) {
-        return context.getResources().getBoolean(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
+        return DisplayCutout.getFillBuiltInDisplayCutout(
+                context.getResources(), context.getDisplay().getUniqueId());
     }
 
     private void updateLayoutParams() {
@@ -1085,7 +1085,8 @@
             int dw = flipped ? lh : lw;
             int dh = flipped ? lw : lh;
 
-            Path path = DisplayCutout.pathFromResources(getResources(), dw, dh);
+            Path path = DisplayCutout.pathFromResources(
+                    getResources(), getDisplay().getUniqueId(), dw, dh);
             if (path != null) {
                 mBoundingPath.set(path);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index affad7a..b126cdd 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -25,6 +25,8 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.res.Resources;
 import android.graphics.RectF;
 import android.os.Handler;
@@ -73,6 +75,9 @@
     private final FlingAnimationUtils mFlingAnimationUtils;
     private float mPagingTouchSlop;
     private final float mSlopMultiplier;
+    private int mTouchSlop;
+    private float mTouchSlopMultiplier;
+
     private final Callback mCallback;
     private final int mSwipeDirection;
     private final VelocityTracker mVelocityTracker;
@@ -105,6 +110,10 @@
                     final int y = (int) mDownLocation[1] - mViewOffset[1];
                     mTouchedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
                     ((ExpandableNotificationRow) mTouchedView).doLongClickCallback(x, y);
+
+                    if (isAvailableToDragAndDrop(mTouchedView)) {
+                        mCallback.onLongPressSent(mTouchedView);
+                    }
                 }
             }
         }
@@ -126,6 +135,8 @@
         mVelocityTracker = VelocityTracker.obtain();
         mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
         mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier();
+        mTouchSlop = viewConfiguration.getScaledTouchSlop();
+        mTouchSlopMultiplier = viewConfiguration.getAmbiguousGestureMultiplier();
 
         // Extra long-press!
         mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
@@ -297,7 +308,9 @@
                 mIsSwiping = false;
                 mSnappingChild = false;
                 mLongPressSent = false;
+                mCallback.onLongPressSent(null);
                 mVelocityTracker.clear();
+                cancelLongPress();
                 mTouchedView = mCallback.getChildAtPosition(ev);
 
                 if (mTouchedView != null) {
@@ -349,6 +362,7 @@
                 mIsSwiping = false;
                 mTouchedView = null;
                 mLongPressSent = false;
+                mCallback.onLongPressSent(null);
                 mMenuRowIntercepting = false;
                 cancelLongPress();
                 if (captured) return true;
@@ -593,11 +607,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mLongPressSent && !mMenuRowIntercepting) {
-            return true;
-        }
-
-        if (!mIsSwiping && !mMenuRowIntercepting) {
+        if (!mIsSwiping && !mMenuRowIntercepting && !mLongPressSent) {
             if (mCallback.getChildAtPosition(ev) != null) {
                 // We are dragging directly over a card, make sure that we also catch the gesture
                 // even if nobody else wants the touch event.
@@ -623,30 +633,40 @@
                     if (absDelta >= getFalsingThreshold()) {
                         mTouchAboveFalsingThreshold = true;
                     }
-                    // don't let items that can't be dismissed be dragged more than
-                    // maxScrollDistance
-                    if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(
-                            mTouchedView,
-                            delta > 0)) {
-                        float size = getSize(mTouchedView);
-                        float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
-                        if (absDelta >= size) {
-                            delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
-                        } else {
-                            int startPosition = mCallback.getConstrainSwipeStartPosition();
-                            if (absDelta > startPosition) {
-                                int signedStartPosition =
-                                        (int) (startPosition * Math.signum(delta));
-                                delta = signedStartPosition
-                                        + maxScrollDistance * (float) Math.sin(
-                                        ((delta - signedStartPosition) / size) * (Math.PI / 2));
+
+                    if (mLongPressSent) {
+                        if (absDelta >= getTouchSlop(ev)) {
+                            if (mTouchedView instanceof ExpandableNotificationRow) {
+                                ((ExpandableNotificationRow) mTouchedView)
+                                        .doDragCallback(ev.getX(), ev.getY());
                             }
                         }
-                    }
+                    } else {
+                        // don't let items that can't be dismissed be dragged more than
+                        // maxScrollDistance
+                        if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(
+                                mTouchedView,
+                                delta > 0)) {
+                            float size = getSize(mTouchedView);
+                            float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
+                            if (absDelta >= size) {
+                                delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
+                            } else {
+                                int startPosition = mCallback.getConstrainSwipeStartPosition();
+                                if (absDelta > startPosition) {
+                                    int signedStartPosition =
+                                            (int) (startPosition * Math.signum(delta));
+                                    delta = signedStartPosition
+                                            + maxScrollDistance * (float) Math.sin(
+                                            ((delta - signedStartPosition) / size) * (Math.PI / 2));
+                                }
+                            }
+                        }
 
-                    setTranslation(mTouchedView, mTranslation + delta);
-                    updateSwipeProgressFromOffset(mTouchedView, mCanCurrViewBeDimissed);
-                    onMoveUpdate(mTouchedView, ev, mTranslation + delta, delta);
+                        setTranslation(mTouchedView, mTranslation + delta);
+                        updateSwipeProgressFromOffset(mTouchedView, mCanCurrViewBeDimissed);
+                        onMoveUpdate(mTouchedView, ev, mTranslation + delta, delta);
+                    }
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -747,6 +767,29 @@
         mIsSwiping = false;
     }
 
+    private float getTouchSlop(MotionEvent event) {
+        // Adjust the touch slop if another gesture may be being performed.
+        return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+                ? mTouchSlop * mTouchSlopMultiplier
+                : mTouchSlop;
+    }
+
+    private boolean isAvailableToDragAndDrop(View v) {
+        if (v.getResources().getBoolean(R.bool.config_notificationToContents)) {
+            if (v instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow enr = (ExpandableNotificationRow) v;
+                boolean canBubble = enr.getEntry().canBubble();
+                Notification notif = enr.getEntry().getSbn().getNotification();
+                PendingIntent dragIntent = notif.contentIntent != null ? notif.contentIntent
+                        : notif.fullScreenIntent;
+                if (dragIntent != null && dragIntent.isActivity() && !canBubble) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public interface Callback {
         View getChildAtPosition(MotionEvent ev);
 
@@ -771,6 +814,13 @@
         void onDragCancelled(View v);
 
         /**
+         * Called when the child is long pressed and available to start drag and drop.
+         *
+         * @param v the view that was long pressed.
+         */
+        void onLongPressSent(View v);
+
+        /**
          * Called when the child is snapped to a position.
          *
          * @param animView the view that was snapped.
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index e880cc8..c6a750a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -23,6 +23,8 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -48,6 +50,7 @@
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
     }
 
+    @VisibleForTesting
     protected void onBootCompleted() {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
rename to packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 6fc2e41..b9440c5 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,35 +13,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui;
+package com.android.systemui.battery;
 
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Handler;
+import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -50,18 +43,14 @@
 import androidx.annotation.StyleRes;
 
 import com.android.settingslib.graph.ThemedBatteryDrawable;
+import com.android.systemui.Dependency;
+import com.android.systemui.DualToneHandler;
+import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -69,8 +58,7 @@
 import java.text.NumberFormat;
 
 public class BatteryMeterView extends LinearLayout implements
-        BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
-
+        BatteryStateChangeCallback, DarkReceiver {
 
     @Retention(SOURCE)
     @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
@@ -81,21 +69,15 @@
     public static final int MODE_ESTIMATE = 3;
 
     private final ThemedBatteryDrawable mDrawable;
-    private final String mSlotBattery;
     private final ImageView mBatteryIconView;
-    private final CurrentUserTracker mUserTracker;
     private TextView mBatteryPercentView;
 
     private BatteryController mBatteryController;
-    private SettingObserver mSettingObserver;
     private final @StyleRes int mPercentageStyleId;
     private int mTextColor;
     private int mLevel;
     private int mShowPercentMode = MODE_DEFAULT;
     private boolean mShowPercentAvailable;
-    // Some places may need to show the battery conditionally, and not obey the tuner
-    private boolean mIgnoreTunerUpdates;
-    private boolean mIsSubscribedForTunerUpdates;
     private boolean mCharging;
     // Error state where we know nothing about the current battery state
     private boolean mBatteryStateUnknown;
@@ -103,7 +85,6 @@
     private Drawable mUnknownStateDrawable;
 
     private DualToneHandler mDualToneHandler;
-    private int mUser;
 
     private int mNonAdaptedSingleToneColor;
     private int mNonAdaptedForegroundColor;
@@ -115,7 +96,6 @@
 
     public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        BroadcastDispatcher broadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
 
         setOrientation(LinearLayout.HORIZONTAL);
         setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
@@ -128,14 +108,11 @@
         mDrawable = new ThemedBatteryDrawable(context, frameColor);
         atts.recycle();
 
-        mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
         mShowPercentAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_battery_percentage_setting_available);
 
         setupLayoutTransition();
 
-        mSlotBattery = context.getString(
-                com.android.internal.R.string.status_bar_battery);
         mBatteryIconView = new ImageView(context);
         mBatteryIconView.setImageDrawable(mDrawable);
         final MarginLayoutParams mlp = new MarginLayoutParams(
@@ -150,21 +127,8 @@
         // Init to not dark at all.
         onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
-        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
-            @Override
-            public void onUserSwitched(int newUserId) {
-                mUser = newUserId;
-                getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
-                getContext().getContentResolver().registerContentObserver(
-                        Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
-                        newUserId);
-                updateShowPercent();
-            }
-        };
-
         setClipChildren(false);
         setClipToPadding(false);
-        Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
     }
 
     private void setupLayoutTransition() {
@@ -196,48 +160,11 @@
      * @param mode desired mode (none, on, off)
      */
     public void setPercentShowMode(@BatteryPercentMode int mode) {
+        if (mode == mShowPercentMode) return;
         mShowPercentMode = mode;
         updateShowPercent();
     }
 
-    /**
-     * Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
-     * thus avoid it controlling its own visibility
-     *
-     * @param ignore whether to ignore the tuner or not
-     */
-    public void setIgnoreTunerUpdates(boolean ignore) {
-        mIgnoreTunerUpdates = ignore;
-        updateTunerSubscription();
-    }
-
-    private void updateTunerSubscription() {
-        if (mIgnoreTunerUpdates) {
-            unsubscribeFromTunerUpdates();
-        } else {
-            subscribeForTunerUpdates();
-        }
-    }
-
-    private void subscribeForTunerUpdates() {
-        if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
-            return;
-        }
-
-        Dependency.get(TunerService.class)
-                .addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
-        mIsSubscribedForTunerUpdates = true;
-    }
-
-    private void unsubscribeFromTunerUpdates() {
-        if (!mIsSubscribedForTunerUpdates) {
-            return;
-        }
-
-        Dependency.get(TunerService.class).removeTunable(this);
-        mIsSubscribedForTunerUpdates = false;
-    }
-
     public void setColorsFromContext(Context context) {
         if (context == null) {
             return;
@@ -252,37 +179,17 @@
     }
 
     @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
-            ArraySet<String> icons = StatusBarIconController.getIconHideList(
-                    getContext(), newValue);
-            setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
-        }
-    }
-
-    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         mBatteryController = Dependency.get(BatteryController.class);
         mBatteryController.addCallback(this);
-        mUser = ActivityManager.getCurrentUser();
-        getContext().getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
-        getContext().getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
-                false, mSettingObserver);
         updateShowPercent();
-        subscribeForTunerUpdates();
-        mUserTracker.startTracking();
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mUserTracker.stopTracking();
         mBatteryController.removeCallback(this);
-        getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
-        unsubscribeFromTunerUpdates();
     }
 
     @Override
@@ -315,7 +222,7 @@
         updateShowPercent();
     }
 
-    private void updatePercentText() {
+    void updatePercentText() {
         if (mBatteryStateUnknown) {
             setContentDescription(getContext().getString(R.string.accessibility_battery_unknown));
             return;
@@ -331,7 +238,7 @@
                     if (mBatteryPercentView == null) {
                         return;
                     }
-                    if (estimate != null) {
+                    if (estimate != null && mShowPercentMode == MODE_ESTIMATE) {
                         mBatteryPercentView.setText(estimate);
                         setContentDescription(getContext().getString(
                                 R.string.accessibility_battery_level_with_estimate,
@@ -361,12 +268,12 @@
                         : R.string.accessibility_battery_level, mLevel));
     }
 
-    private void updateShowPercent() {
+    void updateShowPercent() {
         final boolean showing = mBatteryPercentView != null;
         // TODO(b/140051051)
         final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
                 .getIntForUser(getContext().getContentResolver(),
-                SHOW_BATTERY_PERCENT, 0, mUser));
+                SHOW_BATTERY_PERCENT, 0, UserHandle.USER_CURRENT));
         boolean shouldShow =
                 (mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
                 || mShowPercentMode == MODE_ON
@@ -394,11 +301,6 @@
         }
     }
 
-    @Override
-    public void onDensityOrFontScaleChanged() {
-        scaleBatteryMeterViews();
-    }
-
     private Drawable getUnknownStateDrawable() {
         if (mUnknownStateDrawable == null) {
             mUnknownStateDrawable = mContext.getDrawable(R.drawable.ic_battery_unknown);
@@ -428,7 +330,7 @@
     /**
      * Looks up the scale factor for status bar icons and scales the battery view by that amount.
      */
-    private void scaleBatteryMeterViews() {
+    void scaleBatteryMeterViews() {
         Resources res = getContext().getResources();
         TypedValue typedValue = new TypedValue();
 
@@ -486,22 +388,7 @@
         pw.println("    mTextColor: #" + Integer.toHexString(mTextColor));
         pw.println("    mBatteryStateUnknown: " + mBatteryStateUnknown);
         pw.println("    mLevel: " + mLevel);
-    }
-
-    private final class SettingObserver extends ContentObserver {
-        public SettingObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            super.onChange(selfChange, uri);
-            updateShowPercent();
-            if (TextUtils.equals(uri.getLastPathSegment(),
-                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
-                // update the text for sure if the estimate in the cache was updated
-                updatePercentText();
-            }
-        }
+        pw.println("    mMode: " + mShowPercentMode);
     }
 }
+
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
new file mode 100644
index 0000000..4664423
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.battery;
+
+import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.View;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/** Controller for {@link BatteryMeterView}. **/
+public class BatteryMeterViewController extends ViewController<BatteryMeterView> {
+    private final ConfigurationController mConfigurationController;
+    private final TunerService mTunerService;
+    private final ContentResolver mContentResolver;
+
+    private final String mSlotBattery;
+    private final SettingObserver mSettingObserver;
+    private final CurrentUserTracker mCurrentUserTracker;
+
+    private final ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+                @Override
+                public void onDensityOrFontScaleChanged() {
+                    mView.scaleBatteryMeterViews();
+                }
+            };
+
+    private final TunerService.Tunable mTunable = new TunerService.Tunable() {
+        @Override
+        public void onTuningChanged(String key, String newValue) {
+            if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+                ArraySet<String> icons = StatusBarIconController.getIconHideList(
+                        getContext(), newValue);
+                mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
+            }
+        }
+    };
+
+    // Some places may need to show the battery conditionally, and not obey the tuner
+    private boolean mIgnoreTunerUpdates;
+    private boolean mIsSubscribedForTunerUpdates;
+
+    @Inject
+    public BatteryMeterViewController(
+            BatteryMeterView view,
+            ConfigurationController configurationController,
+            TunerService tunerService,
+            BroadcastDispatcher broadcastDispatcher,
+            @Main Handler mainHandler,
+            ContentResolver contentResolver) {
+        super(view);
+        mConfigurationController = configurationController;
+        mTunerService = tunerService;
+        mContentResolver = contentResolver;
+
+        mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery);
+        mSettingObserver = new SettingObserver(mainHandler);
+        mCurrentUserTracker = new CurrentUserTracker(broadcastDispatcher) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                contentResolver.unregisterContentObserver(mSettingObserver);
+                registerShowBatteryPercentObserver(newUserId);
+                mView.updateShowPercent();
+            }
+        };
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mConfigurationController.addCallback(mConfigurationListener);
+        subscribeForTunerUpdates();
+
+        registerShowBatteryPercentObserver(ActivityManager.getCurrentUser());
+        registerGlobalBatteryUpdateObserver();
+        mCurrentUserTracker.startTracking();
+    }
+
+    @Override
+    protected void onViewDetached() {
+        destroy();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        mConfigurationController.removeCallback(mConfigurationListener);
+        unsubscribeFromTunerUpdates();
+        mCurrentUserTracker.stopTracking();
+        mContentResolver.unregisterContentObserver(mSettingObserver);
+    }
+
+    /**
+     * Turn off {@link BatteryMeterView}'s subscribing to the tuner for updates, and thus avoid it
+     * controlling its own visibility.
+     */
+    public void ignoreTunerUpdates() {
+        mIgnoreTunerUpdates = true;
+        unsubscribeFromTunerUpdates();
+    }
+
+    private void subscribeForTunerUpdates() {
+        if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
+            return;
+        }
+
+        mTunerService.addTunable(mTunable, StatusBarIconController.ICON_HIDE_LIST);
+        mIsSubscribedForTunerUpdates = true;
+    }
+
+    private void unsubscribeFromTunerUpdates() {
+        if (!mIsSubscribedForTunerUpdates) {
+            return;
+        }
+
+        mTunerService.removeTunable(mTunable);
+        mIsSubscribedForTunerUpdates = false;
+    }
+
+    private void registerShowBatteryPercentObserver(int user) {
+        mContentResolver.registerContentObserver(
+                Settings.System.getUriFor(SHOW_BATTERY_PERCENT),
+                false,
+                mSettingObserver,
+                user);
+    }
+
+    private void registerGlobalBatteryUpdateObserver() {
+        mContentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
+                false,
+                mSettingObserver);
+    }
+
+    private final class SettingObserver extends ContentObserver {
+        public SettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            mView.updateShowPercent();
+            if (TextUtils.equals(uri.getLastPathSegment(),
+                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
+                // update the text for sure if the estimate in the cache was updated
+                mView.updatePercentText();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index 205054d..ae3e94b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -44,11 +44,17 @@
     private static final String TAG = "BiometricPrompt/AuthBiometricFaceToFingerprintView";
 
     protected static class UdfpsIconController extends IconController {
+        @BiometricState private int mIconState = STATE_IDLE;
+
         protected UdfpsIconController(
                 @NonNull Context context, @NonNull ImageView iconView, @NonNull TextView textView) {
             super(context, iconView, textView);
         }
 
+        void updateState(@BiometricState int newState) {
+            updateState(mIconState, newState);
+        }
+
         @Override
         protected void updateState(int lastState, int newState) {
             final boolean lastStateIsErrorIcon =
@@ -86,6 +92,7 @@
             }
 
             mState = newState;
+            mIconState = newState;
         }
     }
 
@@ -93,6 +100,8 @@
     @Nullable private ModalityListener mModalityListener;
     @Nullable private FingerprintSensorPropertiesInternal mFingerprintSensorProps;
     @Nullable private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter;
+    @Nullable @VisibleForTesting UdfpsIconController mUdfpsIconController;
+
 
     public AuthBiometricFaceToFingerprintView(Context context) {
         super(context);
@@ -107,6 +116,12 @@
         super(context, attrs, injector);
     }
 
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mUdfpsIconController = new UdfpsIconController(mContext, mIconView, mIndicatorView);
+    }
+
     @Modality
     int getActiveSensorType() {
         return mActiveSensorType;
@@ -168,35 +183,26 @@
     }
 
     @Override
-    @NonNull
-    protected IconController getIconController() {
-        if (mActiveSensorType == TYPE_FINGERPRINT) {
-            if (!(mIconController instanceof UdfpsIconController)) {
-                mIconController = createUdfpsIconController();
-            }
-            return mIconController;
-        }
-        return super.getIconController();
-    }
-
-    @NonNull
-    protected IconController createUdfpsIconController() {
-        return new UdfpsIconController(getContext(), mIconView, mIndicatorView);
-    }
-
-    @Override
     public void updateState(@BiometricState int newState) {
-        if (mState == STATE_HELP || mState == STATE_ERROR) {
-            @Modality final int currentType = mActiveSensorType;
-            mActiveSensorType = TYPE_FINGERPRINT;
+        if (mActiveSensorType == TYPE_FACE) {
+            if (newState == STATE_HELP || newState == STATE_ERROR) {
+                mActiveSensorType = TYPE_FINGERPRINT;
 
-            setRequireConfirmation(false);
-            mConfirmButton.setEnabled(false);
-            mConfirmButton.setVisibility(View.GONE);
+                setRequireConfirmation(false);
+                mConfirmButton.setEnabled(false);
+                mConfirmButton.setVisibility(View.GONE);
 
-            if (mModalityListener != null && currentType != mActiveSensorType) {
-                mModalityListener.onModalitySwitched(currentType, mActiveSensorType);
+                if (mModalityListener != null) {
+                    mModalityListener.onModalitySwitched(TYPE_FACE, mActiveSensorType);
+                }
+
+                // Deactivate the face icon controller so it stops drawing to the view
+                mFaceIconController.deactivate();
+                // Then, activate this icon controller. We need to start in the "idle" state
+                mUdfpsIconController.updateState(STATE_IDLE);
             }
+        } else { // Fingerprint
+            mUdfpsIconController.updateState(newState);
         }
 
         super.updateState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index e8da7c5..c32c1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -49,6 +49,7 @@
         protected Handler mHandler;
         protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark
         protected @BiometricState int mState;
+        protected boolean mDeactivated;
 
         protected IconController(Context context, ImageView iconView, TextView textView) {
             mContext = context;
@@ -67,6 +68,11 @@
         }
 
         protected void animateIcon(int iconRes, boolean repeat) {
+            Log.d(TAG, "animateIcon, state: " + mState + ", deactivated: " + mDeactivated);
+            if (mDeactivated) {
+                return;
+            }
+
             final AnimatedVectorDrawable icon =
                     (AnimatedVectorDrawable) mContext.getDrawable(iconRes);
             mIconView.setImageDrawable(icon);
@@ -92,12 +98,26 @@
         @Override
         public void onAnimationEnd(Drawable drawable) {
             super.onAnimationEnd(drawable);
+            Log.d(TAG, "onAnimationEnd, mState: " + mState + ", deactivated: " + mDeactivated);
+            if (mDeactivated) {
+                return;
+            }
+
             if (mState == STATE_AUTHENTICATING || mState == STATE_HELP) {
                 pulseInNextDirection();
             }
         }
 
+        protected void deactivate() {
+            mDeactivated = true;
+        }
+
         protected void updateState(int lastState, int newState) {
+            if (mDeactivated) {
+                Log.w(TAG, "Ignoring updateState when deactivated: " + newState);
+                return;
+            }
+
             final boolean lastStateIsErrorIcon =
                     lastState == STATE_ERROR || lastState == STATE_HELP;
 
@@ -142,7 +162,7 @@
         }
     }
 
-    protected IconController mIconController;
+    @Nullable @VisibleForTesting IconController mFaceIconController;
 
     public AuthBiometricFaceView(Context context) {
         this(context, null);
@@ -158,6 +178,12 @@
     }
 
     @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mFaceIconController = new IconController(mContext, mIconView, mIndicatorView);
+    }
+
+    @Override
     protected int getDelayAfterAuthenticatedDurationMs() {
         return HIDE_DELAY_MS;
     }
@@ -187,17 +213,9 @@
         return true;
     }
 
-    @NonNull
-    protected IconController getIconController() {
-        if (mIconController == null) {
-            mIconController = new IconController(mContext, mIconView, mIndicatorView);
-        }
-        return mIconController;
-    }
-
     @Override
     public void updateState(@BiometricState int newState) {
-        getIconController().updateState(mState, newState);
+        mFaceIconController.updateState(mState, newState);
 
         if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
                 (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2309d5f..69f9004 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -72,6 +72,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
@@ -123,6 +124,7 @@
     @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Nullable private final UdfpsHbmProvider mHbmProvider;
     @NonNull private final KeyguardBypassController mKeyguardBypassController;
+    @NonNull private final ConfigurationController mConfigurationController;
     @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
@@ -522,7 +524,8 @@
             @NonNull KeyguardStateController keyguardStateController,
             @NonNull KeyguardBypassController keyguardBypassController,
             @NonNull DisplayManager displayManager,
-            @Main Handler mainHandler) {
+            @Main Handler mainHandler,
+            @NonNull ConfigurationController configurationController) {
         mContext = context;
         mExecution = execution;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -557,6 +560,7 @@
                 displayManager,
                 mainHandler);
         mKeyguardBypassController = keyguardBypassController;
+        mConfigurationController = configurationController;
 
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
@@ -776,6 +780,7 @@
                         mDumpManager,
                         mKeyguardViewMediator,
                         mLockscreenShadeTransitionController,
+                        mConfigurationController,
                         this
                 );
             case IUdfpsOverlayController.REASON_AUTH_BP:
@@ -883,11 +888,16 @@
 
     private void onFingerDown(int x, int y, float minor, float major) {
         mExecution.assertIsMainThread();
-        mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
         if (mView == null) {
             Log.w(TAG, "Null view in onFingerDown");
             return;
         }
+
+        if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+                && !mStatusBarStateController.isDozing()) {
+            mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
+        }
+
         if (!mOnFingerDown) {
             playStartHaptic();
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index eb02aa0..d46426a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -22,9 +22,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
@@ -51,17 +49,14 @@
     private UdfpsDrawable mFingerprintDrawable; // placeholder
     private LottieAnimationView mAodFp;
     private LottieAnimationView mLockScreenFp;
-    private int mUdfpsBouncerColor;
-    private int mWallpaperTextColor;
     private int mStatusBarState;
 
     // used when highlighting fp icon:
     private int mTextColorPrimary;
     private ImageView mBgProtection;
     boolean mUdfpsRequested;
-    int mUdfpsRequestedColor;
 
-    private AnimatorSet mAnimatorSet;
+    private AnimatorSet mBackgroundInAnimator = new AnimatorSet();
     private int mAlpha; // 0-255
 
     // AOD anti-burn-in offsets
@@ -72,8 +67,6 @@
     private float mBurnInProgress;
     private float mInterpolatedDarkAmount;
 
-    private ValueAnimator mHintAnimator;
-
     public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mFingerprintDrawable = new UdfpsFpDrawable(context);
@@ -89,23 +82,15 @@
         super.onFinishInflate();
         mAodFp = findViewById(R.id.udfps_aod_fp);
         mLockScreenFp = findViewById(R.id.udfps_lockscreen_fp);
-
         mBgProtection = findViewById(R.id.udfps_keyguard_fp_bg);
 
-        mWallpaperTextColor = Utils.getColorAttrDefaultColor(mContext,
-                R.attr.wallpaperTextColorAccent);
-        mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
-                android.R.attr.textColorPrimary);
+        updateColor();
 
-        // requires call to invalidate to update the color (see #updateColor)
+        // requires call to invalidate to update the color
         mLockScreenFp.addValueCallback(
                 new KeyPath("**"), LottieProperty.COLOR_FILTER,
-                frameInfo -> new PorterDuffColorFilter(getColor(), PorterDuff.Mode.SRC_ATOP)
+                frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
         );
-        mUdfpsRequested = false;
-
-        mHintAnimator = ObjectAnimator.ofFloat(mLockScreenFp, "progress", 1f, 0f, 1f);
-        mHintAnimator.setDuration(4000);
     }
 
     @Override
@@ -148,13 +133,7 @@
     }
 
     void requestUdfps(boolean request, int color) {
-        if (request) {
-            mUdfpsRequestedColor = color;
-        } else {
-            mUdfpsRequestedColor = -1;
-        }
         mUdfpsRequested = request;
-        updateColor();
     }
 
     void setStatusBarState(int statusBarState) {
@@ -162,31 +141,10 @@
     }
 
     void updateColor() {
-        mWallpaperTextColor = Utils.getColorAttrDefaultColor(mContext,
-            R.attr.wallpaperTextColorAccent);
         mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
             android.R.attr.textColorPrimary);
-        mLockScreenFp.invalidate();
-        mBgProtection.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
-    }
-
-    private boolean showingUdfpsBouncer() {
-        return mBgProtection.getVisibility() == View.VISIBLE;
-    }
-
-
-    private int getColor() {
-        if (isUdfpsColorRequested()) {
-            return mUdfpsRequestedColor;
-        } else if (showingUdfpsBouncer()) {
-            return mUdfpsBouncerColor;
-        } else {
-            return mWallpaperTextColor;
-        }
-    }
-
-    private boolean isUdfpsColorRequested() {
-        return mUdfpsRequested && mUdfpsRequestedColor != -1;
+        mBgProtection.setImageDrawable(getContext().getDrawable(R.drawable.fingerprint_bg));
+        mLockScreenFp.invalidate(); // updated with a valueCallback
     }
 
     /**
@@ -200,7 +158,13 @@
     @Override
     protected int updateAlpha() {
         int alpha = super.updateAlpha();
-        mLockScreenFp.setImageAlpha(alpha);
+        mLockScreenFp.setAlpha(alpha / 255f);
+        if (mInterpolatedDarkAmount != 0f) {
+            mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
+        } else {
+            mBgProtection.setAlpha(alpha / 255f);
+        }
+
         return alpha;
     }
 
@@ -213,67 +177,29 @@
     }
 
     void onDozeAmountChanged(float linear, float eased) {
-        mHintAnimator.cancel();
         mInterpolatedDarkAmount = eased;
+        updateAlpha();
         updateBurnInOffsets();
     }
 
-    void animateHint() {
-        if (!isShadeLocked() && !mUdfpsRequested && mAlpha == 255
-                && mLockScreenFp.isVisibleToUser()) {
-            mHintAnimator.start();
-        }
-    }
-
     /**
      * Animates in the bg protection circle behind the fp icon to highlight the icon.
      */
-    void animateUdfpsBouncer(Runnable onEndAnimation) {
-        if (showingUdfpsBouncer() && mBgProtection.getAlpha() == 1f) {
-            // already fully highlighted, don't re-animate
+    void animateInUdfpsBouncer(Runnable onEndAnimation) {
+        if (mBackgroundInAnimator.isRunning()) {
+            // already animating in
             return;
         }
 
-        if (mAnimatorSet != null) {
-            mAnimatorSet.cancel();
-        }
-
-        mAnimatorSet = new AnimatorSet();
-        mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        mAnimatorSet.setDuration(500);
-        mAnimatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mBgProtection.setVisibility(View.VISIBLE);
-            }
-        });
-
-        ValueAnimator fpIconColorAnim;
-        if (isShadeLocked()) {
-            // set color and fade in since we weren't showing before
-            mUdfpsBouncerColor = mTextColorPrimary;
-            fpIconColorAnim = ValueAnimator.ofInt(0, 255);
-            fpIconColorAnim.addUpdateListener(valueAnimator ->
-                    mLockScreenFp.setImageAlpha((int) valueAnimator.getAnimatedValue()));
-        } else {
-            // update icon color
-            fpIconColorAnim = new ValueAnimator();
-            fpIconColorAnim.setIntValues(
-                    isUdfpsColorRequested() ? mUdfpsRequestedColor : mWallpaperTextColor,
-                    mTextColorPrimary);
-            fpIconColorAnim.setEvaluator(ArgbEvaluator.getInstance());
-            fpIconColorAnim.addUpdateListener(valueAnimator -> {
-                mUdfpsBouncerColor = (int) valueAnimator.getAnimatedValue();
-                updateColor();
-            });
-        }
-
-        mAnimatorSet.playTogether(
+        // fade in and scale up
+        mBackgroundInAnimator = new AnimatorSet();
+        mBackgroundInAnimator.playTogether(
                 ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 0f, 1f),
                 ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f),
-                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f),
-                fpIconColorAnim);
-        mAnimatorSet.addListener(new AnimatorListenerAdapter() {
+                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f));
+        mBackgroundInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mBackgroundInAnimator.setDuration(500);
+        mBackgroundInAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (onEndAnimation != null) {
@@ -281,66 +207,7 @@
                 }
             }
         });
-        mAnimatorSet.start();
-    }
-
-    /**
-     * Animates out the bg protection circle behind the fp icon to unhighlight the icon.
-     */
-    void animateAwayUdfpsBouncer(@Nullable Runnable onEndAnimation) {
-        if (!showingUdfpsBouncer()) {
-            // already hidden
-            return;
-        }
-
-        if (mAnimatorSet != null) {
-            mAnimatorSet.cancel();
-        }
-
-        ValueAnimator fpIconColorAnim;
-        if (isShadeLocked()) {
-            // fade out
-            mUdfpsBouncerColor = mTextColorPrimary;
-            fpIconColorAnim = ValueAnimator.ofInt(255, 0);
-            fpIconColorAnim.addUpdateListener(valueAnimator ->
-                    mLockScreenFp.setImageAlpha((int) valueAnimator.getAnimatedValue()));
-        } else {
-            // update icon color
-            fpIconColorAnim = new ValueAnimator();
-            fpIconColorAnim.setIntValues(
-                    mTextColorPrimary,
-                    isUdfpsColorRequested() ? mUdfpsRequestedColor : mWallpaperTextColor);
-            fpIconColorAnim.setEvaluator(ArgbEvaluator.getInstance());
-            fpIconColorAnim.addUpdateListener(valueAnimator -> {
-                mUdfpsBouncerColor = (int) valueAnimator.getAnimatedValue();
-                updateColor();
-            });
-        }
-
-        mAnimatorSet = new AnimatorSet();
-        mAnimatorSet.playTogether(
-                ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 1f, 0f),
-                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 1f, 0f),
-                ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 1f, 0f),
-                fpIconColorAnim);
-        mAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        mAnimatorSet.setDuration(500);
-
-        mAnimatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mBgProtection.setVisibility(View.GONE);
-                if (onEndAnimation != null) {
-                    onEndAnimation.run();
-                }
-            }
-        });
-
-        mAnimatorSet.start();
-    }
-
-    boolean isAnimating() {
-        return mAnimatorSet != null && mAnimatorSet.isRunning();
+        mBackgroundInAnimator.start();
     }
 
     private boolean isShadeLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 9c95720..79a4a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -19,14 +19,11 @@
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 
 import android.annotation.NonNull;
-import android.hardware.biometrics.BiometricSourceType;
+import android.content.res.Configuration;
 import android.util.MathUtils;
 import android.view.MotionEvent;
 
-import androidx.annotation.Nullable;
-
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -36,6 +33,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.io.FileDescriptor;
@@ -45,27 +43,20 @@
 
 /**
  * Class that coordinates non-HBM animations during keyguard authentication.
- *
- * Highlights the udfps icon when:
- * - Face authentication has failed
- * - Face authentication has been run for > 2 seconds
  */
 public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
-    private static final long AFTER_FACE_AUTH_HINT_DELAY = 2000;
-
     @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final DelayableExecutor mExecutor;
     @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
     @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
+    @NonNull private final ConfigurationController mConfigurationController;
     @NonNull private final UdfpsController mUdfpsController;
 
-    @Nullable private Runnable mCancelDelayedHintRunnable;
     private boolean mShowingUdfpsBouncer;
     private boolean mUdfpsRequested;
     private boolean mQsExpanded;
     private boolean mFaceDetectRunning;
-    private boolean mHintShown;
     private int mStatusBarState;
     private float mTransitionToFullShadeProgress;
     private float mLastDozeAmount;
@@ -88,6 +79,7 @@
             @NonNull DumpManager dumpManager,
             @NonNull KeyguardViewMediator keyguardViewMediator,
             @NonNull LockscreenShadeTransitionController transitionController,
+            @NonNull ConfigurationController configurationController,
             @NonNull UdfpsController udfpsController) {
         super(view, statusBarStateController, statusBarOptional, dumpManager);
         mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -95,6 +87,7 @@
         mExecutor = mainDelayableExecutor;
         mKeyguardViewMediator = keyguardViewMediator;
         mLockScreenShadeTransitionController = transitionController;
+        mConfigurationController = configurationController;
         mUdfpsController = udfpsController;
     }
 
@@ -106,10 +99,6 @@
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
-        mHintShown = false;
-        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
-        updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning());
-
         final float dozeAmount = mStatusBarStateController.getDozeAmount();
         mLastDozeAmount = dozeAmount;
         mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
@@ -121,6 +110,7 @@
         mQsExpanded = mKeyguardViewManager.isQsExpanded();
         mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
         mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
+        mConfigurationController.addCallback(mConfigurationListener);
         updateAlpha();
         updatePauseAuth();
 
@@ -131,20 +121,15 @@
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
-        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         mFaceDetectRunning = false;
 
         mStatusBarStateController.removeCallback(mStateListener);
         mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
         mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
+        mConfigurationController.removeCallback(mConfigurationListener);
         if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
             mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
         }
-
-        if (mCancelDelayedHintRunnable != null) {
-            mCancelDelayedHintRunnable.run();
-            mCancelDelayedHintRunnable = null;
-        }
     }
 
     @Override
@@ -159,7 +144,6 @@
         pw.println("mAlpha=" + mView.getAlpha());
         pw.println("mUdfpsRequested=" + mUdfpsRequested);
         pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
-        pw.println("mView.mUdfpsRequestedColor=" + mView.mUdfpsRequestedColor);
     }
 
     /**
@@ -174,12 +158,17 @@
         mShowingUdfpsBouncer = show;
         updatePauseAuth();
         if (mShowingUdfpsBouncer) {
-            mView.animateUdfpsBouncer(() ->
-                    mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true));
+            if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
+                mView.animateInUdfpsBouncer(null);
+            }
+
+            if (mKeyguardViewManager.isOccluded()) {
+                mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
+            }
+
             mView.announceForAccessibility(mView.getContext().getString(
                     R.string.accessibility_fingerprint_bouncer));
         } else {
-            mView.animateAwayUdfpsBouncer(null);
             mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
         }
         return true;
@@ -239,36 +228,6 @@
         }
     }
 
-    private void cancelDelayedHint() {
-        if (mCancelDelayedHintRunnable != null) {
-            mCancelDelayedHintRunnable.run();
-            mCancelDelayedHintRunnable = null;
-        }
-    }
-
-    private void updateFaceDetectRunning(boolean running) {
-        if (mFaceDetectRunning == running) {
-            return;
-        }
-
-        // show udfps hint a few seconds after face auth started running
-        if (!mFaceDetectRunning && running && !mHintShown && mCancelDelayedHintRunnable == null) {
-            // Face detect started running, show udfps hint after a delay
-            mCancelDelayedHintRunnable = mExecutor.executeDelayed(() -> showHint(false),
-                    AFTER_FACE_AUTH_HINT_DELAY);
-        }
-
-        mFaceDetectRunning = running;
-    }
-
-    private void showHint(boolean forceShow) {
-        cancelDelayedHint();
-        if (!mHintShown || forceShow) {
-            mHintShown = true;
-            mView.animateHint();
-        }
-    }
-
     /**
      * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
      * transitioning yet, while 1.0f means we've fully dragged down.
@@ -308,39 +267,6 @@
         }
     };
 
-    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
-            new KeyguardUpdateMonitorCallback() {
-                public void onBiometricRunningStateChanged(boolean running,
-                        BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        updateFaceDetectRunning(running);
-                    }
-                }
-
-                public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // show udfps hint when face auth fails
-                        showHint(true);
-                    }
-                }
-
-                public void onBiometricError(int msgId, String errString,
-                        BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // show udfps hint when face auth fails
-                        showHint(true);
-                    }
-                }
-
-                public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // cancel delayed hint if face auth succeeded
-                        cancelDelayedHint();
-                    }
-                }
-            };
-
     private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor =
             new StatusBarKeyguardViewManager.AlternateAuthInterceptor() {
                 @Override
@@ -367,7 +293,7 @@
 
                 @Override
                 public boolean isAnimating() {
-                    return mView.isAnimating();
+                    return false;
                 }
 
                 @Override
@@ -408,4 +334,27 @@
                     pw.println(getTag());
                 }
             };
+
+    private final ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+                @Override
+                public void onUiModeChanged() {
+                    mView.updateColor();
+                }
+
+                @Override
+                public void onThemeChanged() {
+                    mView.updateColor();
+                }
+
+                @Override
+                public void onOverlayChanged() {
+                    mView.updateColor();
+                }
+
+                @Override
+                public void onConfigChanged(Configuration newConfig) {
+                    mView.updateColor();
+                }
+            };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
index 268ba64..213d13b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -16,22 +16,23 @@
 
 package com.android.systemui.communal;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.AnimatableProperty;
-import com.android.systemui.statusbar.notification.PropertyAnimator;
-import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.concurrent.Executor;
 
@@ -42,22 +43,50 @@
  */
 public class CommunalHostViewController extends ViewController<CommunalHostView> {
     private static final String TAG = "CommunalController";
-    private static final boolean DEBUG = false;
-    private static final AnimationProperties ANIMATION_PROPERTIES =
-            new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String STATE_LIST_FORMAT = "[%s]";
 
     private final Executor mMainExecutor;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final KeyguardStateController mKeyguardStateController;
     private final StatusBarStateController mStatusBarStateController;
     private WeakReference<CommunalSource> mLastSource;
     private int mState;
 
+    @Retention(RetentionPolicy.RUNTIME)
+    @IntDef({STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_BOUNCER_SHOWING, STATE_KEYGUARD_OCCLUDED})
+    public @interface State {}
+
     private static final int STATE_KEYGUARD_SHOWING = 1 << 0;
     private static final int STATE_DOZING = 1 << 1;
+    private static final int STATE_BOUNCER_SHOWING = 1 << 2;
+    private static final int STATE_KEYGUARD_OCCLUDED = 1 << 3;
 
     // Only show communal view when keyguard is showing and not dozing.
     private static final int SHOW_COMMUNAL_VIEW_REQUIRED_STATES = STATE_KEYGUARD_SHOWING;
-    private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES = STATE_DOZING;
+    private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES =
+            STATE_DOZING | STATE_BOUNCER_SHOWING | STATE_KEYGUARD_OCCLUDED;
+
+    private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onKeyguardBouncerChanged(boolean bouncer) {
+                    if (DEBUG) {
+                        Log.d(TAG, "onKeyguardBouncerChanged:" + bouncer);
+                    }
+
+                    setState(STATE_BOUNCER_SHOWING, bouncer);
+                }
+
+                @Override
+                public void onKeyguardOccludedChanged(boolean occluded) {
+                    if (DEBUG) {
+                        Log.d(TAG, "onKeyguardOccludedChanged" + occluded);
+                    }
+
+                    setState(STATE_KEYGUARD_OCCLUDED, occluded);
+                }
+            };
 
     private KeyguardStateController.Callback mKeyguardCallback =
             new KeyguardStateController.Callback() {
@@ -86,44 +115,42 @@
 
     @Inject
     protected CommunalHostViewController(@Main Executor mainExecutor,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController, CommunalHostView view) {
         super(view);
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mMainExecutor = mainExecutor;
         mKeyguardStateController = keyguardStateController;
         mStatusBarStateController = statusBarStateController;
-        mState = 0;
+    }
 
-        if (mKeyguardStateController.isShowing()) {
-            mState |= STATE_KEYGUARD_SHOWING;
-        }
+    @Override
+    public void init() {
+        super.init();
 
-        if (mStatusBarStateController.isDozing()) {
-            mState |= STATE_DOZING;
-        }
-
-        mKeyguardStateController.addCallback(mKeyguardCallback);
-        mStatusBarStateController.addCallback(mDozeCallback);
+        setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+        setState(STATE_DOZING, mStatusBarStateController.isDozing());
     }
 
     @Override
     protected void onViewAttached() {
-        mKeyguardStateController.removeCallback(mKeyguardCallback);
         mKeyguardStateController.addCallback(mKeyguardCallback);
-        mStatusBarStateController.removeCallback(mDozeCallback);
         mStatusBarStateController.addCallback(mDozeCallback);
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
     }
 
     @Override
     protected void onViewDetached() {
         mKeyguardStateController.removeCallback(mKeyguardCallback);
         mStatusBarStateController.removeCallback(mDozeCallback);
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
     }
 
-    private void setState(int stateFlag, boolean enabled) {
+    private void setState(@State int stateFlag, boolean enabled) {
         final int existingState = mState;
         if (DEBUG) {
-            Log.d(TAG, "setState flag:" + stateFlag + " enabled:" + enabled);
+            Log.d(TAG, "setState flag:" + describeState(stateFlag) + " enabled:" + enabled);
         }
 
         if (enabled) {
@@ -133,7 +160,7 @@
         }
 
         if (DEBUG) {
-            Log.d(TAG, "updated state:" + mState);
+            Log.d(TAG, "updated state:" + describeState());
         }
 
         if (existingState != mState) {
@@ -141,12 +168,48 @@
         }
     }
 
+    private String describeState(@State int stateFlag) {
+        switch(stateFlag) {
+            case STATE_DOZING:
+                return "dozing";
+            case STATE_BOUNCER_SHOWING:
+                return "bouncer_showing";
+            case STATE_KEYGUARD_SHOWING:
+                return "keyguard_showing";
+            default:
+                return "UNDEFINED_STATE";
+        }
+    }
+
+    private String describeState() {
+        StringBuilder stringBuilder = new StringBuilder();
+
+        if ((mState & STATE_KEYGUARD_SHOWING) == STATE_KEYGUARD_SHOWING) {
+            stringBuilder.append(String.format(STATE_LIST_FORMAT,
+                    describeState(STATE_KEYGUARD_SHOWING)));
+        }
+        if ((mState & STATE_DOZING) == STATE_DOZING) {
+            stringBuilder.append(String.format(STATE_LIST_FORMAT,
+                    describeState(STATE_DOZING)));
+        }
+        if ((mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING) {
+            stringBuilder.append(String.format(STATE_LIST_FORMAT,
+                    describeState(STATE_BOUNCER_SHOWING)));
+        }
+
+        return stringBuilder.toString();
+    }
+
     private void showSource() {
         // Make sure all necessary states are present for showing communal and all invalid states
         // are absent
         mMainExecutor.execute(() -> {
             final CommunalSource currentSource = mLastSource != null ? mLastSource.get() : null;
 
+            if (DEBUG) {
+                Log.d(TAG, "showSource. currentSource:" + currentSource);
+            }
+
             if ((mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
                     && (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
                     && currentSource != null) {
@@ -192,14 +255,4 @@
         mLastSource = source;
         showSource();
     }
-
-    /**
-     * Sets the Y position of the {@link CommunalHostView}
-     *
-     * @param y       Offset from parent top.
-     * @param animate Whether the change should be animated.
-     */
-    public void updatePositionY(int y, boolean animate) {
-        PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, ANIMATION_PROPERTIES, animate);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
index bcc3684..5f75d86 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java
@@ -16,13 +16,32 @@
 
 package com.android.systemui.communal.dagger;
 
+import android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.idle.dagger.IdleViewComponent;
+
+import javax.inject.Named;
+
 import dagger.Module;
+import dagger.Provides;
 
 /**
  * Dagger Module providing Communal-related functionality.
  */
 @Module(subcomponents = {
         CommunalViewComponent.class,
+        IdleViewComponent.class,
 })
-public class CommunalModule {
+public interface CommunalModule {
+    String IDLE_VIEW = "idle_view";
+
+    /** */
+    @Provides
+    @Named(IDLE_VIEW)
+    static View provideIdleView(Context context) {
+        FrameLayout view = new FrameLayout(context);
+        return view;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
index 7d2006a..d94b8ac5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourceImpl.java
@@ -26,6 +26,7 @@
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 
 import com.android.systemui.communal.CommunalSource;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.communal.ICommunalSource;
 import com.android.systemui.shared.communal.ICommunalSurfaceCallback;
 
@@ -36,6 +37,8 @@
 import java.util.ArrayList;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 /**
  * {@link CommunalSourceImpl} provides a wrapper around {@link ICommunalSource} proxies as an
  * implementation of {@link CommunalSource}. Requests and responses for communal surfaces are
@@ -47,6 +50,19 @@
     private final ICommunalSource mSourceProxy;
     private final Executor mMainExecutor;
 
+    static class Factory {
+        private final Executor mExecutor;
+
+        @Inject
+        Factory(@Main Executor executor) {
+            mExecutor = executor;
+        }
+
+        public CommunalSource create(ICommunalSource source) {
+            return new CommunalSourceImpl(mExecutor, source);
+        }
+    }
+
     // mConnected is initialized to true as it is presumed instances are constructed with valid
     // proxies. The source can never be reconnected once the proxy has died. Once this value
     // becomes false, the source will always report disconnected to registering callbacks.
diff --git a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
index bb3fef3..0f013ff 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/service/CommunalSourcePrimer.java
@@ -16,11 +16,15 @@
 
 package com.android.systemui.communal.service;
 
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.res.Resources;
 import android.os.IBinder;
+import android.os.PatternMatcher;
 import android.util.Log;
 
 import com.android.systemui.R;
@@ -29,8 +33,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.communal.ICommunalSource;
-
-import java.util.concurrent.Executor;
+import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import javax.inject.Inject;
 
@@ -43,63 +46,190 @@
 @SysUISingleton
 public class CommunalSourcePrimer extends SystemUI {
     private static final String TAG = "CommunalSourcePrimer";
-    private static final boolean DEBUG = false;
-    private final Context mContext;
-    private final Executor mMainExecutor;
-    private final CommunalSourceMonitor mMonitor;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String ACTION_COMMUNAL_SOURCE = "android.intent.action.COMMUNAL_SOURCE";
 
+    private final Context mContext;
+    private final DelayableExecutor mMainExecutor;
+    private final CommunalSourceMonitor mMonitor;
+    private final CommunalSourceImpl.Factory mSourceFactory;
+    private final ComponentName mComponentName;
+    private final int mBaseReconnectDelayMs;
+    private final int mMaxReconnectAttempts;
+
+    private int mReconnectAttempts = 0;
+    private Runnable mCurrentReconnectCancelable;
+
+    private final Runnable mConnectRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCurrentReconnectCancelable = null;
+            bindToService();
+        }
+    };
+
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.d(TAG, "package added receiver - onReceive");
+            }
+
+            initiateConnectionAttempt();
+        }
+    };
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             final ICommunalSource source = ICommunalSource.Stub.asInterface(service);
             if (DEBUG) {
-                Log.d(TAG, "onServiceConnected. source;" + source);
+                Log.d(TAG, "onServiceConnected. source:" + source);
             }
 
-            mMonitor.setSource(
-                    source != null ? new CommunalSourceImpl(mMainExecutor, source) : null);
+            if (source == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "onServiceConnected. invalid source");
+                    // Since the service could just repeatedly return null, the primer chooses
+                    // to schedule rather than initiate a new connection attempt sequence.
+                    scheduleConnectionAttempt();
+                }
+                return;
+            }
 
+            mMonitor.setSource(mSourceFactory.create(source));
+        }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            if (DEBUG) {
+                Log.d(TAG, "onBindingDied. lost communal source. initiating reconnect");
+            }
+
+            initiateConnectionAttempt();
         }
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "onServiceDisconnected. lost communal source. initiating reconnect");
+            }
+
+            initiateConnectionAttempt();
         }
     };
 
     @Inject
-    public CommunalSourcePrimer(Context context, @Main Executor mainExecutor,
-            CommunalSourceMonitor monitor) {
+    public CommunalSourcePrimer(Context context, @Main Resources resources,
+            DelayableExecutor mainExecutor,
+            CommunalSourceMonitor monitor,
+            CommunalSourceImpl.Factory sourceFactory) {
         super(context);
         mContext = context;
         mMainExecutor = mainExecutor;
         mMonitor = monitor;
+        mSourceFactory = sourceFactory;
+        mMaxReconnectAttempts = resources.getInteger(
+                R.integer.config_communalSourceMaxReconnectAttempts);
+        mBaseReconnectDelayMs = resources.getInteger(
+                R.integer.config_communalSourceReconnectBaseDelay);
+
+        final String component = resources.getString(R.string.config_communalSourceComponent);
+        mComponentName = component != null && !component.isEmpty()
+                ? ComponentName.unflattenFromString(component) : null;
     }
 
     @Override
     public void start() {
-        if (DEBUG) {
-            Log.d(TAG, "start");
+    }
+
+    private void initiateConnectionAttempt() {
+        // Reset attempts
+        mReconnectAttempts = 0;
+        mMonitor.setSource(null);
+
+        // The first attempt is always a direct invocation rather than delayed.
+        bindToService();
+    }
+
+    private void registerPackageListening() {
+        if (mComponentName == null) {
+            return;
         }
+
+        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addDataScheme("package");
+        filter.addDataSchemeSpecificPart(mComponentName.getPackageName(),
+                PatternMatcher.PATTERN_LITERAL);
+        // Note that we directly register the receiver here as data schemes are not supported by
+        // BroadcastDispatcher.
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void scheduleConnectionAttempt() {
+        // always clear cancelable if present.
+        if (mCurrentReconnectCancelable != null) {
+            mCurrentReconnectCancelable.run();
+            mCurrentReconnectCancelable = null;
+        }
+
+        if (mReconnectAttempts >= mMaxReconnectAttempts) {
+            if (DEBUG) {
+                Log.d(TAG, "exceeded max connection attempts.");
+            }
+            return;
+        }
+
+        final long reconnectDelayMs =
+                (long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts);
+
+        if (DEBUG) {
+            Log.d(TAG,
+                    "scheduling connection attempt in " + reconnectDelayMs + "milliseconds");
+        }
+
+        mCurrentReconnectCancelable = mMainExecutor.executeDelayed(mConnectRunnable,
+                reconnectDelayMs);
+
+        mReconnectAttempts++;
     }
 
     @Override
     protected void onBootCompleted() {
         super.onBootCompleted();
-        final String serviceComponent = mContext.getString(R.string.config_communalSourceComponent);
 
         if (DEBUG) {
-            Log.d(TAG, "onBootCompleted. communal source component:" + serviceComponent);
+            Log.d(TAG, "onBootCompleted. communal source component:" + mComponentName);
         }
 
-        if (serviceComponent == null || serviceComponent.isEmpty()) {
+        registerPackageListening();
+        initiateConnectionAttempt();
+    }
+
+    private void bindToService() {
+        if (mComponentName == null) {
             return;
         }
 
+        if (DEBUG) {
+            Log.d(TAG, "attempting to bind to communal source");
+        }
+
         final Intent intent = new Intent();
         intent.setAction(ACTION_COMMUNAL_SOURCE);
-        intent.setComponent(ComponentName.unflattenFromString(serviceComponent));
+        intent.setComponent(mComponentName);
 
-        mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        final boolean binding = mContext.bindService(intent, Context.BIND_AUTO_CREATE,
+                mMainExecutor, mConnection);
+
+        if (!binding) {
+            if (DEBUG) {
+                Log.d(TAG, "bindService failed, rescheduling");
+            }
+
+            scheduleConnectionAttempt();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 239a77e..9cb9a36 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -39,6 +39,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.recents.Recents;
@@ -80,6 +81,7 @@
  */
 @Module(includes = {
         MediaModule.class,
+        PowerModule.class,
         QSModule.class
 })
 public abstract class SystemUIDefaultModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b42d65a..3d90ede 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -37,18 +37,17 @@
 import com.android.systemui.demomode.dagger.DemoModeModule;
 import com.android.systemui.doze.dagger.DozeComponent;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.log.dagger.LogModule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.screenshot.dagger.ScreenshotModule;
 import com.android.systemui.settings.dagger.SettingsModule;
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -104,7 +103,6 @@
             FalsingModule.class,
             LogModule.class,
             PeopleHubModule.class,
-            PowerModule.class,
             PluginModule.class,
             ScreenshotModule.class,
             SensorModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 23c4413..b2db86f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -115,6 +115,7 @@
         mSecureSettings = secureSettings;
         mCallback = callback;
         mProximitySensor = proximitySensor;
+        mProximitySensor.setTag(TAG);
         mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx();
         mListeningProxSensors = !mSelectivelyRegisterProxSensors;
         mScreenOffUdfpsEnabled =
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
index 6fbf81c..d4d01c8 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.flags;
 
+import android.content.Context;
 import android.content.res.Resources;
 import android.util.SparseArray;
 
@@ -25,7 +26,9 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.plugins.FlagReaderPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.wrapper.BuildInfo;
 
 import javax.inject.Inject;
@@ -55,18 +58,68 @@
 public class FeatureFlagReader {
     private final Resources mResources;
     private final boolean mAreFlagsOverrideable;
+    private final PluginManager mPluginManager;
     private final SystemPropertiesHelper mSystemPropertiesHelper;
     private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>();
 
+    private FlagReaderPlugin mPlugin = new FlagReaderPlugin(){};
+
     @Inject
     public FeatureFlagReader(
             @Main Resources resources,
             BuildInfo build,
+            PluginManager pluginManager,
             SystemPropertiesHelper systemPropertiesHelper) {
         mResources = resources;
+        mPluginManager = pluginManager;
         mSystemPropertiesHelper = systemPropertiesHelper;
         mAreFlagsOverrideable =
                 build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable);
+
+        mPluginManager.addPluginListener(mPluginListener, FlagReaderPlugin.class);
+    }
+
+    private final PluginListener<FlagReaderPlugin> mPluginListener =
+            new PluginListener<FlagReaderPlugin>() {
+                public void onPluginConnected(FlagReaderPlugin plugin, Context context) {
+                    mPlugin = plugin;
+                }
+
+                public void onPluginDisconnected(FlagReaderPlugin plugin) {
+                    mPlugin = new FlagReaderPlugin() {};
+                }
+            };
+
+    boolean isEnabled(BooleanFlag flag) {
+        return mPlugin.isEnabled(flag.getId(), flag.getDefault());
+    }
+
+    String getValue(StringFlag flag) {
+        return mPlugin.getValue(flag.getId(), flag.getDefault());
+    }
+
+    int getValue(IntFlag flag) {
+        return mPlugin.getValue(flag.getId(), flag.getDefault());
+    }
+
+    long getValue(LongFlag flag) {
+        return mPlugin.getValue(flag.getId(), flag.getDefault());
+    }
+
+    float getValue(FloatFlag flag) {
+        return mPlugin.getValue(flag.getId(), flag.getDefault());
+    }
+
+    double getValue(DoubleFlag flag) {
+        return mPlugin.getValue(flag.getId(), flag.getDefault());
+    }
+
+    void addListener(FlagReaderPlugin.Listener listener) {
+        mPlugin.addListener(listener);
+    }
+
+    void removeListener(FlagReaderPlugin.Listener listener) {
+        mPlugin.removeListener(listener);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
new file mode 100644
index 0000000..e51f90f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.FlagReaderPlugin;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Class to manage simple DeviceConfig-based feature flags.
+ *
+ * See {@link FeatureFlagReader} for instructions on defining and flipping flags.
+ */
+@SysUISingleton
+public class FeatureFlags {
+    private final FeatureFlagReader mFlagReader;
+    private final Context mContext;
+    private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>();
+    private final Map<Integer, List<Listener>> mListeners = new HashMap<>();
+
+    @Inject
+    public FeatureFlags(FeatureFlagReader flagReader, Context context) {
+        mFlagReader = flagReader;
+        mContext = context;
+
+        flagReader.addListener(mListener);
+    }
+
+    private final FlagReaderPlugin.Listener mListener = id -> {
+        if (mListeners.containsKey(id) && mFlagMap.containsKey(id)) {
+            mListeners.get(id).forEach(listener -> listener.onFlagChanged(mFlagMap.get(id)));
+        }
+    };
+
+    @VisibleForTesting
+    void addFlag(Flag flag) {
+        mFlagMap.put(flag.getId(), flag);
+    }
+
+    /**
+     * @param flag The {@link BooleanFlag} of interest.
+     * @return The value of the flag.
+     */
+    public boolean isEnabled(BooleanFlag flag) {
+        return mFlagReader.isEnabled(flag);
+    }
+
+    /**
+     * @param flag The {@link StringFlag} of interest.
+     * @return The value of the flag.
+     */
+    public String getValue(StringFlag flag) {
+        return mFlagReader.getValue(flag);
+    }
+
+    /**
+     * @param flag The {@link IntFlag} of interest.
+     * @return The value of the flag.
+     */
+    public int getValue(IntFlag flag) {
+        return mFlagReader.getValue(flag);
+    }
+
+    /**
+     * @param flag The {@link LongFlag} of interest.
+     * @return The value of the flag.
+     */
+    public long getValue(LongFlag flag) {
+        return mFlagReader.getValue(flag);
+    }
+
+    /**
+     * @param flag The {@link FloatFlag} of interest.
+     * @return The value of the flag.
+     */
+    public float getValue(FloatFlag flag) {
+        return mFlagReader.getValue(flag);
+    }
+
+    /**
+     * @param flag The {@link DoubleFlag} of interest.
+     * @return The value of the flag.
+     */
+    public double getValue(DoubleFlag flag) {
+        return mFlagReader.getValue(flag);
+    }
+
+    /** Add a listener for a specific flag. */
+    public void addFlagListener(Flag<?> flag, Listener listener) {
+        mListeners.putIfAbsent(flag.getId(), new ArrayList<>());
+        mListeners.get(flag.getId()).add(listener);
+        mFlagMap.putIfAbsent(flag.getId(), flag);
+    }
+
+    /** Remove a listener for a specific flag. */
+    public void removeFlagListener(Flag<?> flag, Listener listener) {
+        if (mListeners.containsKey(flag.getId())) {
+            mListeners.get(flag.getId()).remove(listener);
+        }
+    }
+
+    public boolean isNewNotifPipelineEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2);
+    }
+
+    public boolean isNewNotifPipelineRenderingEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
+    }
+
+    public boolean isKeyguardLayoutEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
+    }
+
+    /** */
+    public boolean useNewLockscreenAnimations() {
+        return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
+    }
+
+    public boolean isPeopleTileEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_conversations);
+    }
+
+    public boolean isMonetEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_monet);
+    }
+
+    public boolean isPMLiteEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_pm_lite);
+    }
+
+    public boolean isChargingRippleEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
+    }
+
+    public boolean isOngoingCallStatusBarChipEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip);
+    }
+
+    public boolean isSmartspaceEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_smartspace);
+    }
+
+    public boolean isSmartspaceDedupingEnabled() {
+        return isSmartspaceEnabled() && mFlagReader.isEnabled(R.bool.flag_smartspace_deduping);
+    }
+
+    public boolean isNewKeyguardSwipeAnimationEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_new_unlock_swipe_animation);
+    }
+
+    public boolean isSmartSpaceSharedElementTransitionEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_smartspace_shared_element_transition);
+    }
+
+    /** Whether or not to use the provider model behavior for the status bar icons */
+    public boolean isCombinedStatusBarSignalIconsEnabled() {
+        return mFlagReader.isEnabled(R.bool.flag_combined_status_bar_signal_icons);
+    }
+
+    /** System setting for provider model behavior */
+    public boolean isProviderModelSettingEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
+    }
+
+    /** static method for the system setting */
+    public static boolean isProviderModelSettingEnabled(Context context) {
+        return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
+    }
+
+    /** Simple interface for beinga alerted when a specific flag changes value. */
+    public interface Listener {
+        /** */
+        void onFlagChanged(Flag<?> flag);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java
new file mode 100644
index 0000000..7d79279
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostView.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.idle;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * {@link IdleHostView} houses a surface to be displayed when the device idle.
+ */
+public class IdleHostView extends FrameLayout {
+    public IdleHostView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public IdleHostView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public IdleHostView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
new file mode 100644
index 0000000..38af02b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.idle;
+
+import static com.android.systemui.communal.dagger.CommunalModule.IDLE_VIEW;
+
+import android.annotation.IntDef;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.service.dreams.Sandman;
+import android.util.Log;
+import android.view.Choreographer;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+/**
+ * {@link IdleHostViewController} processes signals to control the lifecycle of the idle screen.
+ */
+public class IdleHostViewController extends ViewController<IdleHostView> implements
+        SensorEventListener {
+    private static final String INPUT_MONITOR_IDENTIFIER = "IdleHostViewController";
+    private static final String TAG = "IdleHostViewController";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @IntDef({STATE_IDLE_MODE_ENABLED, STATE_DOZING, STATE_KEYGUARD_SHOWING, STATE_IDLING})
+    public @interface State {}
+
+    // Set at construction to indicate idle mode is available.
+    private static final int STATE_IDLE_MODE_ENABLED = 1 << 0;
+
+    // Set when the device has entered a system level dream.
+    private static final int STATE_DOZING = 1 << 1;
+
+    // Set when the keyguard is showing.
+    private static final int STATE_KEYGUARD_SHOWING = 1 << 2;
+
+    // Set when input monitoring has established the device is now idling.
+    private static final int STATE_IDLING = 1 << 3;
+
+    // Set when the device is in a low light environment.
+    private static final int STATE_LOW_LIGHT = 1 << 4;
+
+    // The state the controller must be in to start recognizing idleness (lack of input
+    // interaction).
+    private static final int CONDITIONS_IDLE_MONITORING =
+            STATE_IDLE_MODE_ENABLED | STATE_KEYGUARD_SHOWING;
+
+    // The state the controller must be in before entering idle mode.
+    private static final int CONDITIONS_IDLING = CONDITIONS_IDLE_MONITORING | STATE_IDLING;
+
+    // The state the controller must be in to start listening for low light signals.
+    private static final int CONDITIONS_LOW_LIGHT_MONITORING =
+            STATE_IDLE_MODE_ENABLED | STATE_KEYGUARD_SHOWING;
+
+    // The aggregate current state.
+    private int mState;
+    private boolean mIdleModeActive;
+    private boolean mLowLightModeActive;
+    private boolean mIsMonitoringLowLight;
+
+    private final Context mContext;
+
+    // Timeout to idle in milliseconds.
+    private final int mIdleTimeout;
+
+    // Factory for generating input listeners.
+    private final InputMonitorFactory mInputMonitorFactory;
+
+    // Delayable executor.
+    private final DelayableExecutor mDelayableExecutor;
+
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
+    private final PowerManager mPowerManager;
+
+    private final AsyncSensorManager mSensorManager;
+
+    // Light sensor used to detect low light condition.
+    private final Sensor mSensor;
+
+    // Runnable for canceling enabling idle.
+    private Runnable mCancelEnableIdling;
+
+    // Keyguard state controller for monitoring keyguard show state.
+    private final KeyguardStateController mKeyguardStateController;
+
+    // Status bar state controller for monitoring when the device is dozing.
+    private final StatusBarStateController mStatusBarStateController;
+
+    // Looper to use for monitoring input.
+    private final Looper mLooper;
+
+    // Choreographer to use for monitoring input.
+    private final Choreographer mChoreographer;
+
+    // Monitor for tracking touches for activity.
+    private InputMonitorCompat mInputMonitor;
+
+    // Delayed callback for enabling idle mode.
+    private final Runnable mEnableIdlingCallback = () -> {
+        if (DEBUG) {
+            Log.d(TAG, "enabling idle");
+        }
+        setState(STATE_IDLING, true);
+    };
+
+    private final KeyguardStateController.Callback mKeyguardCallback =
+            new KeyguardStateController.Callback() {
+                @Override
+                public void onKeyguardShowingChanged() {
+                    setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+                }
+            };
+
+    private final StatusBarStateController.StateListener mStatusBarCallback =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onDozingChanged(boolean isDozing) {
+                    setState(STATE_DOZING, isDozing);
+                }
+            };
+
+    private final BroadcastReceiver mDreamEndedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+                setState(STATE_IDLING, false);
+            }
+        }
+    };
+
+    final Provider<View> mIdleViewProvider;
+
+    @Inject
+    protected IdleHostViewController(
+            Context context,
+            BroadcastDispatcher broadcastDispatcher,
+            PowerManager powerManager,
+            AsyncSensorManager sensorManager,
+            IdleHostView view, InputMonitorFactory factory,
+            @Main DelayableExecutor delayableExecutor,
+            @Main Resources resources,
+            @Main Looper looper,
+            @Named(IDLE_VIEW) Provider<View> idleViewProvider,
+            Choreographer choreographer,
+            KeyguardStateController keyguardStateController,
+            StatusBarStateController statusBarStateController) {
+        super(view);
+        mContext = context;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mPowerManager = powerManager;
+        mSensorManager = sensorManager;
+        mIdleViewProvider = idleViewProvider;
+        mKeyguardStateController = keyguardStateController;
+        mStatusBarStateController = statusBarStateController;
+        mLooper = looper;
+        mChoreographer = choreographer;
+
+        mState = STATE_KEYGUARD_SHOWING;
+
+        final boolean enabled = resources.getBoolean(R.bool.config_enableIdleMode);
+        if (enabled) {
+            mState |= STATE_IDLE_MODE_ENABLED;
+        }
+
+        setState(mState, true);
+
+        mIdleTimeout = resources.getInteger(R.integer.config_idleModeTimeout);
+        mInputMonitorFactory = factory;
+        mDelayableExecutor = delayableExecutor;
+        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+
+        if (DEBUG) {
+            Log.d(TAG, "initial state:" + mState + " enabled:" + enabled
+                    + " timeout:" + mIdleTimeout);
+        }
+    }
+
+    @Override
+    public void init() {
+        super.init();
+
+        setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
+        setState(STATE_DOZING, mStatusBarStateController.isDozing());
+    }
+
+    private void setState(@State int state, boolean active) {
+        final int oldState = mState;
+
+        if (active) {
+            mState |= state;
+        } else {
+            mState &= ~state;
+        }
+
+        // If we have entered doze or no longer match the preconditions for idling, remove idling.
+        if ((mState & STATE_DOZING) == STATE_DOZING
+                || (mState & CONDITIONS_IDLE_MONITORING) != CONDITIONS_IDLE_MONITORING) {
+            mState &= ~STATE_IDLING;
+        }
+
+        if (oldState == mState) {
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "state changed from " + oldState + " to " + mState);
+        }
+
+        enableIdleMonitoring(mState == CONDITIONS_IDLE_MONITORING);
+        enableIdleMode(mState == CONDITIONS_IDLING);
+        // Loose matching. Doesn't need to be the exact state to monitor low light, but only
+        // the specified states need to match.
+        enableLowLightMonitoring(
+                (mState & CONDITIONS_LOW_LIGHT_MONITORING) == CONDITIONS_LOW_LIGHT_MONITORING);
+        enableLowLightMode((mState & STATE_LOW_LIGHT) == STATE_LOW_LIGHT);
+    }
+
+    private void enableIdleMonitoring(boolean enable) {
+        if (enable && mInputMonitor == null) {
+            if (DEBUG) {
+                Log.d(TAG, "enable idle monitoring");
+            }
+            // Set initial timeout to idle.
+            mCancelEnableIdling = mDelayableExecutor.executeDelayed(mEnableIdlingCallback,
+                    mIdleTimeout);
+
+            // Monitor - any input should reset timer
+            mInputMonitor = mInputMonitorFactory.getInputMonitor(INPUT_MONITOR_IDENTIFIER);
+            mInputMonitor.getInputReceiver(mLooper, mChoreographer,
+                    v -> {
+                        if (DEBUG) {
+                            Log.d(TAG, "touch detected, resetting timeout");
+                        }
+                        // When input is received, reset timeout.
+                        if (mCancelEnableIdling != null) {
+                            mCancelEnableIdling.run();
+                            mCancelEnableIdling = null;
+                        }
+                        mCancelEnableIdling = mDelayableExecutor.executeDelayed(
+                                mEnableIdlingCallback, mIdleTimeout);
+                    });
+        } else if (!enable && mInputMonitor != null) {
+            if (DEBUG) {
+                Log.d(TAG, "disable idle monitoring");
+            }
+            // Clean up idle callback and touch monitoring.
+            if (mCancelEnableIdling != null) {
+                mCancelEnableIdling.run();
+                mCancelEnableIdling = null;
+            }
+
+            mInputMonitor.dispose();
+            mInputMonitor = null;
+        }
+    }
+
+    private void enableIdleMode(boolean enable) {
+        if (mIdleModeActive == enable) {
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "enable idle mode:" + enable);
+        }
+
+        mIdleModeActive = enable;
+
+        if (mIdleModeActive) {
+            // Track when the dream ends to cancel any timeouts.
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+            mBroadcastDispatcher.registerReceiver(mDreamEndedReceiver, filter);
+
+            // Start dream.
+            Sandman.startDreamByUserRequest(mContext);
+        } else {
+            // Stop tracking dream end.
+            mBroadcastDispatcher.unregisterReceiver(mDreamEndedReceiver);
+        }
+    }
+
+    private void enableLowLightMonitoring(boolean enable) {
+        if (enable == mIsMonitoringLowLight) {
+            return;
+        }
+
+        mIsMonitoringLowLight = enable;
+
+        if (mIsMonitoringLowLight) {
+            if (DEBUG) Log.d(TAG, "Enabling low light monitoring.");
+            mSensorManager.registerListener(this /*listener*/, mSensor,
+                    SensorManager.SENSOR_DELAY_NORMAL);
+        } else {
+            if (DEBUG) Log.d(TAG, "Disabling low light monitoring.");
+            mSensorManager.unregisterListener(this);
+        }
+    }
+
+    private void enableLowLightMode(boolean enable) {
+        if (mLowLightModeActive == enable) {
+            return;
+        }
+
+        mLowLightModeActive = enable;
+
+        if (mLowLightModeActive) {
+            if (DEBUG) Log.d(TAG, "Entering low light, start dozing.");
+
+            mPowerManager.goToSleep(
+                    SystemClock.uptimeMillis(),
+                    PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
+        } else {
+            if (DEBUG) Log.d(TAG, "Exiting low light, stop dozing.");
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                    PowerManager.WAKE_REASON_APPLICATION, "Exit low light condition");
+        }
+    }
+
+    @Override
+    protected void onViewAttached() {
+        if (DEBUG) {
+            Log.d(TAG, "onViewAttached");
+        }
+
+        mKeyguardStateController.addCallback(mKeyguardCallback);
+        mStatusBarStateController.addCallback(mStatusBarCallback);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mKeyguardStateController.removeCallback(mKeyguardCallback);
+        mStatusBarStateController.removeCallback(mStatusBarCallback);
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.values.length == 0) {
+            if (DEBUG) Log.w(TAG, "SensorEvent doesn't have value");
+            return;
+        }
+
+        final boolean isLowLight = event.values[0] < 10;
+        setState(STATE_LOW_LIGHT, isLowLight);
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        if (DEBUG) {
+            Log.d(TAG, "onAccuracyChanged accuracy=" + accuracy);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java b/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java
new file mode 100644
index 0000000..be0a378
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/InputMonitorFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.idle;
+
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import javax.inject.Inject;
+
+/**
+ * {@link InputMonitorFactory} generates instances of {@link InputMonitorCompat}.
+ */
+public class InputMonitorFactory {
+    private final int mDisplayId;
+
+    @Inject
+    public InputMonitorFactory(@DisplayId int displayId) {
+        mDisplayId = displayId;
+    }
+
+    /**
+     * Generates a new {@link InputMonitorCompat}.
+     *
+     * @param identifier Identifier to generate monitor with.
+     * @return A {@link InputMonitorCompat} instance.
+     */
+    public InputMonitorCompat getInputMonitor(String identifier) {
+        return new InputMonitorCompat(identifier, mDisplayId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.java b/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.java
new file mode 100644
index 0000000..9754b1f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/dagger/IdleViewComponent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.idle.dagger;
+
+import com.android.systemui.idle.IdleHostView;
+import com.android.systemui.idle.IdleHostViewController;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Subcomponent for working with {@link IdleHostView}.
+ */
+@Subcomponent
+public interface IdleViewComponent {
+    /** Simple factory for {@link Factory}. */
+    @Subcomponent.Factory
+    interface Factory {
+        IdleViewComponent build(@BindsInstance IdleHostView idleHostView);
+    }
+
+    /** Builds a {@link IdleHostViewController}. */
+    IdleHostViewController getIdleHostViewController();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 62b92cb..0b8c635 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -18,14 +18,32 @@
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionOldType;
+import static android.view.WindowManager.TransitionType;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
 
+import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.Service;
+import android.app.WindowConfiguration;
 import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -42,8 +60,13 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
@@ -51,8 +74,11 @@
 import com.android.internal.policy.IKeyguardService;
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.systemui.SystemUIApplication;
+import com.android.wm.shell.transition.ShellTransitions;
 import com.android.wm.shell.transition.Transitions;
 
+import java.util.ArrayList;
+
 import javax.inject.Inject;
 
 public class KeyguardService extends Service {
@@ -79,40 +105,196 @@
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
     public static boolean sEnableRemoteKeyguardGoingAwayAnimation =
-            !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 1;
+            sEnableRemoteKeyguardAnimation >= 1;
 
     /**
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
     public static boolean sEnableRemoteKeyguardOccludeAnimation =
-            !Transitions.ENABLE_SHELL_TRANSITIONS && sEnableRemoteKeyguardAnimation >= 2;
+            sEnableRemoteKeyguardAnimation >= 2;
 
     private final KeyguardViewMediator mKeyguardViewMediator;
     private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
 
+    private static int newModeToLegacyMode(int newMode) {
+        switch (newMode) {
+            case WindowManager.TRANSIT_OPEN:
+            case WindowManager.TRANSIT_TO_FRONT:
+                return MODE_OPENING;
+            case WindowManager.TRANSIT_CLOSE:
+            case WindowManager.TRANSIT_TO_BACK:
+                return MODE_CLOSING;
+            default:
+                return 2; // MODE_CHANGING
+        }
+    }
+
+    private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers) {
+        final ArrayList<RemoteAnimationTarget> out = new ArrayList<>();
+        for (int i = 0; i < info.getChanges().size(); i++) {
+            boolean changeIsWallpaper =
+                    (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
+            if (wallpapers != changeIsWallpaper) continue;
+
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+            final int taskId = taskInfo != null ? change.getTaskInfo().taskId : -1;
+            boolean isNotInRecents;
+            WindowConfiguration windowConfiguration = null;
+            if (taskInfo != null) {
+                if (taskInfo.getConfiguration() != null) {
+                    windowConfiguration =
+                            change.getTaskInfo().getConfiguration().windowConfiguration;
+                }
+                isNotInRecents = !change.getTaskInfo().isRunning;
+            } else {
+                isNotInRecents = true;
+            }
+            Rect localBounds = new Rect(change.getEndAbsBounds());
+            localBounds.offsetTo(change.getEndRelOffset().x, change.getEndRelOffset().y);
+
+            out.add(new RemoteAnimationTarget(
+                    taskId,
+                    newModeToLegacyMode(change.getMode()),
+                    change.getLeash(),
+                    (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0
+                            || (change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0,
+                    null /* clipRect */,
+                    new Rect(0, 0, 0, 0) /* contentInsets */,
+                    info.getChanges().size() - i,
+                    new Point(), localBounds, new Rect(change.getEndAbsBounds()),
+                    windowConfiguration, isNotInRecents, null /* startLeash */,
+                    change.getStartAbsBounds(), taskInfo, false /* allowEnterPip */));
+        }
+        return out.toArray(new RemoteAnimationTarget[out.size()]);
+    }
+
+    private static @TransitionOldType int getTransitionOldType(@TransitionType int type,
+            RemoteAnimationTarget[] apps) {
+        if (type == TRANSIT_KEYGUARD_GOING_AWAY) {
+            return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+                    : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+        } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+            return TRANSIT_OLD_KEYGUARD_OCCLUDE;
+        } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
+            return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
+        } else {
+            Slog.d(TAG, "Unexpected transit type: " + type);
+            return TRANSIT_OLD_NONE;
+        }
+    }
+
+    private static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
+        return new IRemoteTransition.Stub() {
+            @Override
+            public void startAnimation(IBinder transition, TransitionInfo info,
+                    SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+                    throws RemoteException {
+                Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
+                final RemoteAnimationTarget[] apps = wrap(info, false /* wallpapers */);
+                final RemoteAnimationTarget[] wallpapers = wrap(info, true /* wallpapers */);
+                final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
+
+                // TODO: Remove this, and update alpha value in the IAnimationRunner.
+                for (TransitionInfo.Change change : info.getChanges()) {
+                    t.setAlpha(change.getLeash(), 1.0f);
+                }
+                t.apply();
+                runner.onAnimationStart(getTransitionOldType(info.getType(), apps),
+                        apps, wallpapers, nonApps,
+                        new IRemoteAnimationFinishedCallback.Stub() {
+                            @Override
+                            public void onAnimationFinished() throws RemoteException {
+                                Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+                                finishCallback.onTransitionFinished(null /* wct */, null /* t */);
+                            }
+                        }
+                );
+            }
+
+            public void mergeAnimation(IBinder transition, TransitionInfo info,
+                    SurfaceControl.Transaction t, IBinder mergeTarget,
+                    IRemoteTransitionFinishedCallback finishCallback) {
+
+            }
+        };
+    }
+
     @Inject
     public KeyguardService(KeyguardViewMediator keyguardViewMediator,
-                           KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher) {
+                           KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
+                           ShellTransitions shellTransitions) {
         super();
         mKeyguardViewMediator = keyguardViewMediator;
         mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
 
-        RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
-        if (sEnableRemoteKeyguardGoingAwayAnimation) {
-            final RemoteAnimationAdapter exitAnimationAdapter =
-                    new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
-            definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, exitAnimationAdapter);
-            definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
-                    exitAnimationAdapter);
+        if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
+            if (sEnableRemoteKeyguardGoingAwayAnimation) {
+                Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
+                TransitionFilter f = new TransitionFilter();
+                f.mTypeSet = new int[]{TRANSIT_KEYGUARD_GOING_AWAY};
+                shellTransitions.registerRemote(f, wrap(mExitAnimationRunner));
+            }
+            if (sEnableRemoteKeyguardOccludeAnimation) {
+                Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
+                // Register for occluding
+                TransitionFilter f = new TransitionFilter();
+                f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+                f.mRequirements = new TransitionFilter.Requirement[]{
+                        new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+                // First require at-least one app showing that occludes.
+                f.mRequirements[0].mMustBeIndependent = false;
+                f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+                f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+                // Then require that we aren't closing any occludes (because this would mean a
+                // regular task->task or activity->activity animation not involving keyguard).
+                f.mRequirements[1].mNot = true;
+                f.mRequirements[1].mMustBeIndependent = false;
+                f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
+                f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+                shellTransitions.registerRemote(f, mOccludeAnimation);
+
+                // Now register for un-occlude.
+                f = new TransitionFilter();
+                f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+                f.mRequirements = new TransitionFilter.Requirement[]{
+                        new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+                // First require at-least one app going-away (doesn't need occlude flag
+                // as that is implicit by it having been visible and we don't want to exclude
+                // cases where we are un-occluding because the app removed its showWhenLocked
+                // capability at runtime).
+                f.mRequirements[1].mMustBeIndependent = false;
+                f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+                f.mRequirements[1].mMustBeTask = true;
+                // Then require that we aren't opening any occludes (otherwise we'd remain
+                // occluded).
+                f.mRequirements[0].mNot = true;
+                f.mRequirements[0].mMustBeIndependent = false;
+                f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+                f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+                shellTransitions.registerRemote(f, mUnoccludeAnimation);
+            }
+        } else {
+            RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+            if (sEnableRemoteKeyguardGoingAwayAnimation) {
+                final RemoteAnimationAdapter exitAnimationAdapter =
+                        new RemoteAnimationAdapter(mExitAnimationRunner, 0, 0);
+                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
+                        exitAnimationAdapter);
+                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+                        exitAnimationAdapter);
+            }
+            if (sEnableRemoteKeyguardOccludeAnimation) {
+                final RemoteAnimationAdapter occludeAnimationAdapter =
+                        new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
+                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
+                        occludeAnimationAdapter);
+                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE,
+                        occludeAnimationAdapter);
+            }
+            ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
+                    DEFAULT_DISPLAY, definition);
         }
-        if (sEnableRemoteKeyguardOccludeAnimation) {
-            final RemoteAnimationAdapter occludeAnimationAdapter =
-                    new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
-            definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE, occludeAnimationAdapter);
-            definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, occludeAnimationAdapter);
-        }
-        ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
-                DEFAULT_DISPLAY, definition);
     }
 
     @Override
@@ -145,10 +327,10 @@
                 RemoteAnimationTarget[] wallpapers,
                 RemoteAnimationTarget[] nonApps,
                 IRemoteAnimationFinishedCallback finishedCallback) {
-            Trace.beginSection("KeyguardService.mBinder#startKeyguardExitAnimation");
+            Trace.beginSection("mExitAnimationRunner.onAnimationStart#startKeyguardExitAnimation");
             checkPermission();
             mKeyguardViewMediator.startKeyguardExitAnimation(transit, apps, wallpapers,
-                    null /* nonApps */, finishedCallback);
+                    nonApps, finishedCallback);
             Trace.endSection();
         }
 
@@ -166,14 +348,14 @@
                        RemoteAnimationTarget[] wallpapers,
                         RemoteAnimationTarget[] nonApps,
                         IRemoteAnimationFinishedCallback finishedCallback) {
+            Slog.d(TAG, "mOccludeAnimationRunner.onAnimationStart: transit=" + transit);
             try {
                 if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
                     mBinder.setOccluded(true /* isOccluded */, true /* animate */);
                 } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) {
                     mBinder.setOccluded(false /* isOccluded */, true /* animate */);
                 }
-                // TODO(bc-unlock): Implement occlude/unocclude animation applied on apps,
-                //  wallpapers and nonApps.
+                // TODO(bc-unlock): Implement (un)occlude animation.
                 finishedCallback.onAnimationFinished();
             } catch (RemoteException e) {
                 Slog.e(TAG, "RemoteException");
@@ -185,6 +367,40 @@
         }
     };
 
+    final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() {
+        @Override
+        public void startAnimation(IBinder transition, TransitionInfo info,
+                SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+                    throws RemoteException {
+            t.apply();
+            mBinder.setOccluded(true /* isOccluded */, true /* animate */);
+            finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+        }
+
+        @Override
+        public void mergeAnimation(IBinder transition, TransitionInfo info,
+                SurfaceControl.Transaction t, IBinder mergeTarget,
+                IRemoteTransitionFinishedCallback finishCallback) {
+        }
+    };
+
+    final IRemoteTransition mUnoccludeAnimation = new IRemoteTransition.Stub() {
+        @Override
+        public void startAnimation(IBinder transition, TransitionInfo info,
+                SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+                throws RemoteException {
+            t.apply();
+            mBinder.setOccluded(false /* isOccluded */, true /* animate */);
+            finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+        }
+
+        @Override
+        public void mergeAnimation(IBinder transition, TransitionInfo info,
+                SurfaceControl.Transaction t, IBinder mergeTarget,
+                IRemoteTransitionFinishedCallback finishCallback) {
+        }
+    };
+
     private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
 
         @Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index a5fe9015..e51b602 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -31,7 +31,7 @@
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import dagger.Lazy
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d12c763..2817718 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -399,6 +399,12 @@
     private boolean mPendingLock;
 
     /**
+     * When starting to go away, flag a need to show the PIN lock so the keyguard can be brought
+     * back.
+     */
+    private boolean mPendingPinLock = false;
+
+    /**
      * Whether a power button gesture (such as double tap for camera) has been detected. This is
      * delivered directly from {@link KeyguardService}, immediately upon the gesture being detected.
      * This is used in {@link #onStartedWakingUp} to decide whether to execute the pending lock, or
@@ -472,6 +478,19 @@
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
+        public void onKeyguardVisibilityChanged(boolean showing) {
+            synchronized (KeyguardViewMediator.this) {
+                if (!showing && mPendingPinLock) {
+                    Log.i(TAG, "PIN lock requested, starting keyguard");
+
+                    // Bring the keyguard back in order to show the PIN lock
+                    mPendingPinLock = false;
+                    doKeyguardLocked(null);
+                }
+            }
+        }
+
+        @Override
         public void onUserSwitching(int userId) {
             if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
             // Note that the mLockPatternUtils user has already been updated from setCurrentUser.
@@ -591,6 +610,7 @@
                                     + "showing; need to show keyguard so user can enter sim pin");
                             doKeyguardLocked(null);
                         } else {
+                            mPendingPinLock = true;
                             resetStateLocked();
                         }
                     }
@@ -739,6 +759,9 @@
         @Override
         public void onBouncerVisiblityChanged(boolean shown) {
             synchronized (KeyguardViewMediator.this) {
+                if (shown) {
+                    mPendingPinLock = false;
+                }
                 adjustStatusBarLocked(shown, false);
             }
         }
@@ -2324,8 +2347,8 @@
     }
 
     private Configuration.Builder createInteractionJankMonitorConf(String tag) {
-        return new Configuration.Builder(CUJ_LOCKSCREEN_UNLOCK_ANIMATION)
-                .setView(mKeyguardViewControllerLazy.get().getViewRootImpl().getView())
+        return Configuration.Builder.withView(CUJ_LOCKSCREEN_UNLOCK_ANIMATION,
+                mKeyguardViewControllerLazy.get().getViewRootImpl().getView())
                 .setTag(tag);
     }
 
@@ -2580,7 +2603,7 @@
             if (mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_guestUserAutoCreated)) {
                 // TODO(b/191067027): Move post-boot guest creation to system_server
-                mUserSwitcherController.guaranteeGuestPresent();
+                mUserSwitcherController.schedulePostBootGuestCreation();
             }
             mBootCompleted = true;
             adjustStatusBarLocked(false, true);
@@ -2736,7 +2759,10 @@
 
         // Don't hide the keyguard due to a doze change if there's a lock pending, because we're
         // just going to show it again.
-        if (mShowing || !mPendingLock) {
+        // If the device is not capable of controlling the screen off animation, SysUI needs to
+        // update lock screen state in ATMS here, otherwise ATMS tries to resume activities when
+        // enabling doze state.
+        if (mShowing || !mPendingLock || !mDozeParameters.canControlUnlockedScreenOff()) {
             setShowingLocked(mShowing);
         }
     }
@@ -2783,7 +2809,7 @@
         }
     }
 
-    private void setShowingLocked(boolean showing) {
+    void setShowingLocked(boolean showing) {
         setShowingLocked(showing, false /* forceCallbacks */);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 2016215..4a67e94 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -597,6 +597,7 @@
     }
 
     public void destroyView() {
+        setAutoHideController(/* autoHideController */ null);
         mCommandQueue.removeCallback(this);
         mContext.getSystemService(WindowManager.class).removeViewImmediate(
                 mNavigationBarView.getRootView());
@@ -919,6 +920,11 @@
 
     @Override
     public void onRotationProposal(final int rotation, boolean isValid) {
+        // The CommandQueue callbacks are added when the view is created to ensure we track other
+        // states, but until the view is attached (at the next traversal), the view's display is
+        // not valid.  Just ignore the rotation in this case.
+        if (!mNavigationBarView.isAttachedToWindow()) return;
+
         final int winRotation = mNavigationBarView.getDisplay().getRotation();
         final boolean rotateSuggestionsDisabled = RotationButtonController
                 .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -1484,7 +1490,7 @@
     }
 
     /** Sets {@link AutoHideController} to the navigation bar. */
-    public void setAutoHideController(AutoHideController autoHideController) {
+    private void setAutoHideController(AutoHideController autoHideController) {
         mAutoHideController = autoHideController;
         if (mAutoHideController != null) {
             mAutoHideController.setNavigationBar(mAutoHideUiElement);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 458c50d..1ca2217 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -116,7 +116,7 @@
     private final TaskbarDelegate mTaskbarDelegate;
     private final NotificationShadeDepthController mNotificationShadeDepthController;
     private int mNavMode;
-    private boolean mIsTablet;
+    @VisibleForTesting boolean mIsTablet;
     private final UserTracker mUserTracker;
 
     /** A displayId - nav bar maps. */
@@ -402,7 +402,6 @@
     void removeNavigationBar(int displayId) {
         NavigationBar navBar = mNavigationBars.get(displayId);
         if (navBar != null) {
-            navBar.setAutoHideController(/* autoHideController */ null);
             navBar.destroyView();
             mNavigationBars.remove(displayId);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 808b7e2..2d36de3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -98,6 +98,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 public class NavigationBarView extends FrameLayout implements
@@ -354,6 +355,7 @@
         mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class)
                 .create(mContext);
         mEdgeBackGestureHandler.setStateChangeCallback(this::updateStates);
+        Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
         mRegionSamplingHelper = new RegionSamplingHelper(this,
                 new RegionSamplingHelper.SamplingCallback() {
                     @Override
@@ -376,7 +378,7 @@
                     public boolean isSamplingEnabled() {
                         return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode);
                     }
-                });
+                }, backgroundExecutor);
 
         mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
         if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 7fdb79e..ea04cef 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -58,6 +58,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 
 import java.io.PrintWriter;
+import java.util.concurrent.Executor;
 
 public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPlugin {
 
@@ -349,6 +350,7 @@
                 .getDimension(R.dimen.navigation_edge_action_drag_threshold);
         setVisibility(GONE);
 
+        Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
         boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
         mRegionSamplingHelper = new RegionSamplingHelper(this,
                 new RegionSamplingHelper.SamplingCallback() {
@@ -366,7 +368,7 @@
                     public boolean isSamplingEnabled() {
                         return isPrimaryDisplay;
                     }
-                });
+                }, backgroundExecutor);
         mRegionSamplingHelper.setWindowVisible(true);
         mShowProtection = !isPrimaryDisplay;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
index 560d89a..c9a9399 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 
 import java.io.PrintWriter;
+import java.util.concurrent.Executor;
 
 /**
  * A helper class to sample regions on the screen and inspect its luminosity.
@@ -52,6 +53,7 @@
      */
     private final Rect mRegisteredSamplingBounds = new Rect();
     private final SamplingCallback mCallback;
+    private final Executor mBackgroundExecutor;
     private boolean mSamplingEnabled = false;
     private boolean mSamplingListenerRegistered = false;
 
@@ -82,7 +84,9 @@
         }
     };
 
-    public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback) {
+    public RegionSamplingHelper(View sampledView, SamplingCallback samplingCallback,
+            Executor backgroundExecutor) {
+        mBackgroundExecutor = backgroundExecutor;
         mSamplingListener = new CompositionSamplingListener(
                 sampledView.getContext().getMainExecutor()) {
             @Override
@@ -183,10 +187,13 @@
                 // We only want to reregister if something actually changed
                 unregisterSamplingListener();
                 mSamplingListenerRegistered = true;
-                CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
-                        stopLayerControl, mSamplingRequestBounds);
+                SurfaceControl registeredStopLayer = stopLayerControl;
+                mBackgroundExecutor.execute(() -> {
+                    CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+                            registeredStopLayer, mSamplingRequestBounds);
+                });
                 mRegisteredSamplingBounds.set(mSamplingRequestBounds);
-                mRegisteredStopLayer = stopLayerControl;
+                mRegisteredStopLayer = registeredStopLayer;
             }
             mFirstSamplingAfterStart = false;
         } else {
@@ -199,7 +206,9 @@
             mSamplingListenerRegistered = false;
             mRegisteredStopLayer = null;
             mRegisteredSamplingBounds.setEmpty();
-            CompositionSamplingListener.unregister(mSamplingListener);
+            mBackgroundExecutor.execute(() -> {
+                CompositionSamplingListener.unregister(mSamplingListener);
+            });
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ce1066e..1bd3664 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -268,7 +268,7 @@
     }
 
     @Override
-    public void setExpansion(float expansion) {
+    public void setExpansion(float expansion, float proposedTranslation) {
         mLastExpansion = expansion;
         updateSelected();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index adcaf5d..a128694 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -29,13 +29,17 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.qs.customize.QSCustomizer;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link QuickStatusBarHeader}
  */
-public class QSContainerImpl extends FrameLayout {
+public class QSContainerImpl extends FrameLayout implements Dumpable {
 
     private final Point mSizePoint = new Point();
     private int mFancyClippingTop;
@@ -302,4 +306,11 @@
                 mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
         invalidate();
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(getClass().getSimpleName() + " updateClippingPath: top("
+                + mFancyClippingTop + ") bottom(" + mFancyClippingBottom  + ") mClippingEnabled("
+                + mClippingEnabled + ")");
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index e38bd4b..0e0681b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -35,11 +35,6 @@
     void setExpanded(boolean expanded);
 
     /**
-     * Returns the full height of the footer.
-     */
-    int getHeight();
-
-    /**
      * Sets the percentage amount that the quick settings has been expanded.
      *
      * @param expansion A value from 1 to 0 that indicates how much the quick settings have been
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
new file mode 100644
index 0000000..dbf62a4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
@@ -0,0 +1,167 @@
+package com.android.systemui.qs
+
+import android.content.Intent
+import android.os.UserManager
+import android.provider.Settings
+import android.view.View
+import android.widget.Toast
+import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.nano.MetricsProto
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.globalactions.GlobalActionsDialogLite
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
+import com.android.systemui.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.phone.SettingsButton
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.ViewController
+import javax.inject.Inject
+import javax.inject.Named
+
+class QSFooterActionsController @Inject constructor(
+    view: QSFooterActionsView,
+    private val qsPanelController: QSPanelController,
+    private val activityStarter: ActivityStarter,
+    private val userManager: UserManager,
+    private val userInfoController: UserInfoController,
+    private val multiUserSwitchController: MultiUserSwitchController,
+    private val deviceProvisionedController: DeviceProvisionedController,
+    private val falsingManager: FalsingManager,
+    private val metricsLogger: MetricsLogger,
+    private val tunerService: TunerService,
+    private val globalActionsDialog: GlobalActionsDialogLite,
+    private val uiEventLogger: UiEventLogger,
+    @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean
+) : ViewController<QSFooterActionsView>(view) {
+
+    private var listening: Boolean = false
+    var expanded = false
+        set(value) {
+            field = value
+            mView.setExpanded(value, isTunerEnabled(),
+                    multiUserSwitchController.isMultiUserEnabled)
+        }
+
+    private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
+    private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
+    private val editButton: View = view.findViewById(android.R.id.edit)
+    private val powerMenuLite: View = view.findViewById(R.id.pm_lite)
+
+    private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
+        val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
+        mView.onUserInfoChanged(picture, isGuestUser)
+    }
+
+    private val onClickListener = View.OnClickListener { v ->
+        // Don't do anything until views are unhidden. Don't do anything if the tap looks
+        // suspicious.
+        if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return@OnClickListener
+        }
+        if (v === settingsButton) {
+            if (!deviceProvisionedController.isCurrentUserSetup) {
+                // If user isn't setup just unlock the device and dump them back at SUW.
+                activityStarter.postQSRunnableDismissingKeyguard {}
+                return@OnClickListener
+            }
+            metricsLogger.action(
+                    if (expanded) MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
+                    else MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH)
+            if (settingsButton.isTunerClick) {
+                activityStarter.postQSRunnableDismissingKeyguard {
+                    if (isTunerEnabled()) {
+                        tunerService.showResetRequest {
+                            // Relaunch settings so that the tuner disappears.
+                            startSettingsActivity()
+                        }
+                    } else {
+                        Toast.makeText(context, R.string.tuner_toast, Toast.LENGTH_LONG).show()
+                        tunerService.isTunerEnabled = true
+                    }
+                    startSettingsActivity()
+                }
+            } else {
+                startSettingsActivity()
+            }
+        } else if (v === powerMenuLite) {
+            uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
+            globalActionsDialog.showOrHideDialog(false, true)
+        }
+    }
+
+    override fun onInit() {
+        multiUserSwitchController.init()
+    }
+
+    private fun startSettingsActivity() {
+        val animationController = settingsButtonContainer?.let {
+            ActivityLaunchAnimator.Controller.fromView(
+                    it,
+                    InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON)
+            }
+        activityStarter.startActivity(Intent(Settings.ACTION_SETTINGS),
+                true /* dismissShade */, animationController)
+    }
+
+    @VisibleForTesting
+    public override fun onViewAttached() {
+        if (showPMLiteButton) {
+            powerMenuLite.visibility = View.VISIBLE
+            powerMenuLite.setOnClickListener(onClickListener)
+        } else {
+            powerMenuLite.visibility = View.GONE
+        }
+        settingsButton.setOnClickListener(onClickListener)
+        editButton.setOnClickListener(View.OnClickListener { view: View? ->
+            if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+                return@OnClickListener
+            }
+            activityStarter.postQSRunnableDismissingKeyguard { qsPanelController.showEdit(view) }
+        })
+
+        mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+    }
+
+    override fun onViewDetached() {
+        setListening(false)
+    }
+
+    fun setListening(listening: Boolean) {
+        if (this.listening == listening) {
+            return
+        }
+        this.listening = listening
+        if (this.listening) {
+            userInfoController.addCallback(onUserInfoChangedListener)
+        } else {
+            userInfoController.removeCallback(onUserInfoChangedListener)
+        }
+    }
+
+    fun disable(state2: Int) {
+        mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+    }
+
+    fun setExpansion(headerExpansionFraction: Float) {
+        mView.setExpansion(headerExpansionFraction)
+    }
+
+    fun updateAnimator(width: Int, numTiles: Int) {
+        mView.updateAnimator(width, numTiles)
+    }
+
+    fun setKeyguardShowing() {
+        mView.setKeyguardShowing()
+    }
+
+    private fun isTunerEnabled() = tunerService.isTunerEnabled
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
new file mode 100644
index 0000000..66a29a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs
+
+import android.app.StatusBarManager
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.PorterDuff
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.RippleDrawable
+import android.os.UserManager
+import android.util.AttributeSet
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import com.android.settingslib.Utils
+import com.android.settingslib.drawable.UserIconDrawable
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.MultiUserSwitch
+import com.android.systemui.statusbar.phone.SettingsButton
+
+/**
+ * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS,
+ * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings,
+ * edit tiles, power off and conditionally: user switch and tuner
+ */
+class QSFooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
+    private lateinit var settingsContainer: View
+    private lateinit var settingsButton: SettingsButton
+    private lateinit var multiUserSwitch: MultiUserSwitch
+    private lateinit var multiUserAvatar: ImageView
+    private lateinit var tunerIcon: View
+    private lateinit var editTilesButton: View
+
+    private var settingsCogAnimator: TouchAnimator? = null
+
+    private var qsDisabled = false
+    private var isExpanded = false
+    private var expansionAmount = 0f
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        editTilesButton = requireViewById(android.R.id.edit)
+        settingsButton = findViewById(R.id.settings_button)
+        settingsContainer = findViewById(R.id.settings_button_container)
+        multiUserSwitch = findViewById(R.id.multi_user_switch)
+        multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar)
+        tunerIcon = requireViewById(R.id.tuner_icon)
+
+        // RenderThread is doing more harm than good when touching the header (to expand quick
+        // settings), so disable it for this view
+        if (settingsButton.background is RippleDrawable) {
+            (settingsButton.background as RippleDrawable).setForceSoftware(true)
+        }
+        updateResources()
+        importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
+    }
+
+    fun updateAnimator(width: Int, numTiles: Int) {
+        val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) -
+                mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding))
+        val remaining = (width - numTiles * size) / (numTiles - 1)
+        val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space)
+        val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace)
+        settingsCogAnimator = TouchAnimator.Builder()
+                .addFloat(settingsButton, "translationX", translation.toFloat(), 0f)
+                .addFloat(settingsButton, "rotation", -120f, 0f)
+                .build()
+        setExpansion(expansionAmount)
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        updateResources()
+    }
+
+    override fun onRtlPropertiesChanged(layoutDirection: Int) {
+        super.onRtlPropertiesChanged(layoutDirection)
+        updateResources()
+    }
+
+    private fun updateResources() {
+        val tunerIconTranslation = mContext.resources
+                .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat()
+        tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation
+    }
+
+    fun setKeyguardShowing() {
+        setExpansion(expansionAmount)
+    }
+
+    fun setExpanded(expanded: Boolean, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+        if (isExpanded == expanded) return
+        isExpanded = expanded
+        updateEverything(isTunerEnabled, multiUserEnabled)
+    }
+
+    fun setExpansion(headerExpansionFraction: Float) {
+        expansionAmount = headerExpansionFraction
+        if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction)
+    }
+
+    fun disable(state2: Int, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+        val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
+        if (disabled == qsDisabled) return
+        qsDisabled = disabled
+        updateEverything(isTunerEnabled, multiUserEnabled)
+    }
+
+    fun updateEverything(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+        post {
+            updateVisibilities(isTunerEnabled, multiUserEnabled)
+            updateClickabilities()
+            isClickable = false
+        }
+    }
+
+    private fun updateClickabilities() {
+        multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE
+        editTilesButton.isClickable = editTilesButton.visibility == VISIBLE
+        settingsButton.isClickable = settingsButton.visibility == VISIBLE
+    }
+
+    private fun updateVisibilities(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+        settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
+        tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
+        multiUserSwitch.visibility = if (showUserSwitcher(multiUserEnabled)) VISIBLE else GONE
+        val isDemo = UserManager.isDeviceInDemoMode(context)
+        settingsButton.visibility = if (isDemo || !isExpanded) INVISIBLE else VISIBLE
+    }
+
+    private fun showUserSwitcher(multiUserEnabled: Boolean): Boolean {
+        return isExpanded && multiUserEnabled
+    }
+
+    fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {
+        var pictureToSet = picture
+        if (picture != null && isGuestUser && picture !is UserIconDrawable) {
+            pictureToSet = picture.constantState.newDrawable(resources).mutate()
+            pictureToSet.setColorFilter(
+                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground),
+                    PorterDuff.Mode.SRC_IN)
+        }
+        multiUserAvatar.setImageDrawable(pictureToSet)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 57438d1..7db13bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -21,60 +21,40 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.settingslib.Utils;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
-import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.systemui.R;
-import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.statusbar.phone.MultiUserSwitch;
-import com.android.systemui.statusbar.phone.SettingsButton;
 
-/** */
+/**
+ * Footer of expanded Quick Settings, tiles page indicator, (optionally) build number and
+ * {@link QSFooterActionsView}
+ */
 public class QSFooterView extends FrameLayout {
-    private SettingsButton mSettingsButton;
-    protected View mSettingsContainer;
     private PageIndicator mPageIndicator;
     private TextView mBuildText;
-    private boolean mShouldShowBuildText;
-
-    private boolean mQsDisabled;
-
-    private boolean mExpanded;
-
-    private boolean mListening;
-
-    protected MultiUserSwitch mMultiUserSwitch;
-    private ImageView mMultiUserAvatar;
+    private View mActionsContainer;
 
     protected TouchAnimator mFooterAnimator;
+
+    private boolean mQsDisabled;
+    private boolean mExpanded;
     private float mExpansionAmount;
 
-    protected View mEdit;
-    private TouchAnimator mSettingsCogAnimator;
-
-    private View mActionsContainer;
-    private View mTunerIcon;
-    private int mTunerIconTranslation;
+    private boolean mShouldShowBuildText;
 
     private OnClickListener mExpandClickListener;
 
@@ -94,27 +74,11 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mEdit = requireViewById(android.R.id.edit);
-
         mPageIndicator = findViewById(R.id.footer_page_indicator);
-
-        mSettingsButton = findViewById(R.id.settings_button);
-        mSettingsContainer = findViewById(R.id.settings_button_container);
-
-        mMultiUserSwitch = findViewById(R.id.multi_user_switch);
-        mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
-
         mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
         mBuildText = findViewById(R.id.build);
-        mTunerIcon = requireViewById(R.id.tuner_icon);
 
-        // RenderThread is doing more harm than good when touching the header (to expand quick
-        // settings), so disable it for this view
-        if (mSettingsButton.getBackground() instanceof RippleDrawable) {
-            ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
-        }
         updateResources();
-
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         setBuildText();
     }
@@ -137,18 +101,7 @@
         }
     }
 
-    void updateAnimator(int width, int numTiles) {
-        int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
-                - mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding);
-        int remaining = (width - numTiles * size) / (numTiles - 1);
-        int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
-
-        mSettingsCogAnimator = new Builder()
-                .addFloat(mSettingsButton, "translationX",
-                        isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
-                .addFloat(mSettingsButton, "rotation", -120, 0)
-                .build();
-
+    void updateExpansion() {
         setExpansion(mExpansionAmount);
     }
 
@@ -158,20 +111,11 @@
         updateResources();
     }
 
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-        updateResources();
-    }
-
     private void updateResources() {
         updateFooterAnimator();
         MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
         lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
         setLayoutParams(lp);
-        mTunerIconTranslation = mContext.getResources()
-                .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation);
-        mTunerIcon.setTranslationX(isLayoutRtl() ? -mTunerIconTranslation : mTunerIconTranslation);
     }
 
     private void updateFooterAnimator() {
@@ -197,17 +141,15 @@
         mExpandClickListener = onClickListener;
     }
 
-    void setExpanded(boolean expanded, boolean isTunerEnabled, boolean multiUserEnabled) {
+    void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
-        updateEverything(isTunerEnabled, multiUserEnabled);
+        updateEverything();
     }
 
     /** */
     public void setExpansion(float headerExpansionFraction) {
         mExpansionAmount = headerExpansionFraction;
-        if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
-
         if (mFooterAnimator != null) {
             mFooterAnimator.setPosition(headerExpansionFraction);
         }
@@ -228,14 +170,6 @@
         super.onDetachedFromWindow();
     }
 
-    /** */
-    public void setListening(boolean listening) {
-        if (listening == mListening) {
-            return;
-        }
-        mListening = listening;
-    }
-
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
         if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
@@ -253,50 +187,26 @@
         info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
     }
 
-    void disable(int state2, boolean isTunerEnabled, boolean multiUserEnabled) {
+    void disable(int state2) {
         final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
         if (disabled == mQsDisabled) return;
         mQsDisabled = disabled;
-        updateEverything(isTunerEnabled, multiUserEnabled);
+        updateEverything();
     }
 
-    void updateEverything(boolean isTunerEnabled, boolean multiUserEnabled) {
+    void updateEverything() {
         post(() -> {
-            updateVisibilities(isTunerEnabled, multiUserEnabled);
+            updateVisibilities();
             updateClickabilities();
             setClickable(false);
         });
     }
 
     private void updateClickabilities() {
-        mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
-        mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
-        mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
         mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
     }
 
-    private void updateVisibilities(boolean isTunerEnabled, boolean multiUserEnabled) {
-        mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
-        mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE);
-        final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
-        mMultiUserSwitch.setVisibility(
-                showUserSwitcher(multiUserEnabled) ? View.VISIBLE : View.GONE);
-        mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
-
+    private void updateVisibilities() {
         mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE);
     }
-
-    private boolean showUserSwitcher(boolean multiUserEnabled) {
-        return mExpanded && multiUserEnabled;
-    }
-
-    void onUserInfoChanged(Drawable picture, boolean isGuestUser) {
-        if (picture != null && isGuestUser && !(picture instanceof UserIconDrawable)) {
-            picture = picture.getConstantState().newDrawable(getResources()).mutate();
-            picture.setColorFilter(
-                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground),
-                    Mode.SRC_IN);
-        }
-        mMultiUserAvatar.setImageDrawable(picture);
-    }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 929aeda..c8ae590 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,39 +16,19 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
-
 import android.content.ClipData;
 import android.content.ClipboardManager;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.UserManager;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.globalactions.GlobalActionsDialogLite;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitchController;
-import com.android.systemui.statusbar.phone.SettingsButton;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 
 /**
  * Controller for {@link QSFooterView}.
@@ -56,137 +36,45 @@
 @QSScope
 public class QSFooterViewController extends ViewController<QSFooterView> implements QSFooter {
 
-    private final UserManager mUserManager;
-    private final UserInfoController mUserInfoController;
-    private final ActivityStarter mActivityStarter;
-    private final DeviceProvisionedController mDeviceProvisionedController;
     private final UserTracker mUserTracker;
     private final QSPanelController mQsPanelController;
     private final QuickQSPanelController mQuickQSPanelController;
-    private final TunerService mTunerService;
-    private final MetricsLogger mMetricsLogger;
-    private final FalsingManager mFalsingManager;
-    private final MultiUserSwitchController mMultiUserSwitchController;
-    private final SettingsButton mSettingsButton;
-    private final View mSettingsButtonContainer;
+    private final QSFooterActionsController mQsFooterActionsController;
     private final TextView mBuildText;
-    private final View mEdit;
     private final PageIndicator mPageIndicator;
-    private final View mPowerMenuLite;
-    private final boolean mShowPMLiteButton;
-    private final GlobalActionsDialogLite mGlobalActionsDialog;
-    private final UiEventLogger mUiEventLogger;
-
-    private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
-            new UserInfoController.OnUserInfoChangedListener() {
-        @Override
-        public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
-            boolean isGuestUser = mUserManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser());
-            mView.onUserInfoChanged(picture, isGuestUser);
-        }
-    };
-
-    private final View.OnClickListener mSettingsOnClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            // Don't do anything until views are unhidden. Don't do anything if the tap looks
-            // suspicious.
-            if (!mExpanded || mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                return;
-            }
-
-            if (v == mSettingsButton) {
-                if (!mDeviceProvisionedController.isCurrentUserSetup()) {
-                    // If user isn't setup just unlock the device and dump them back at SUW.
-                    mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
-                    });
-                    return;
-                }
-                mMetricsLogger.action(
-                        mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
-                                : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
-                if (mSettingsButton.isTunerClick()) {
-                    mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
-                        if (isTunerEnabled()) {
-                            mTunerService.showResetRequest(
-                                    () -> {
-                                        // Relaunch settings so that the tuner disappears.
-                                        startSettingsActivity();
-                                    });
-                        } else {
-                            Toast.makeText(getContext(), R.string.tuner_toast,
-                                    Toast.LENGTH_LONG).show();
-                            mTunerService.setTunerEnabled(true);
-                        }
-                        startSettingsActivity();
-
-                    });
-                } else {
-                    startSettingsActivity();
-                }
-            } else if (v == mPowerMenuLite) {
-                mUiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
-                mGlobalActionsDialog.showOrHideDialog(false, true);
-            }
-        }
-    };
-
-    private boolean mListening;
-    private boolean mExpanded;
 
     @Inject
-    QSFooterViewController(QSFooterView view, UserManager userManager,
-            UserInfoController userInfoController, ActivityStarter activityStarter,
-            DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
+    QSFooterViewController(QSFooterView view,
+            UserTracker userTracker,
             QSPanelController qsPanelController,
-            MultiUserSwitchController multiUserSwitchController,
             QuickQSPanelController quickQSPanelController,
-            TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
-            @Named(PM_LITE_ENABLED) boolean showPMLiteButton,
-            GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger) {
+            QSFooterActionsController qsFooterActionsController) {
         super(view);
-        mUserManager = userManager;
-        mUserInfoController = userInfoController;
-        mActivityStarter = activityStarter;
-        mDeviceProvisionedController = deviceProvisionedController;
         mUserTracker = userTracker;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
-        mTunerService = tunerService;
-        mMetricsLogger = metricsLogger;
-        mFalsingManager = falsingManager;
-        mMultiUserSwitchController = multiUserSwitchController;
+        mQsFooterActionsController = qsFooterActionsController;
 
-        mSettingsButton = mView.findViewById(R.id.settings_button);
-        mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container);
         mBuildText = mView.findViewById(R.id.build);
-        mEdit = mView.findViewById(android.R.id.edit);
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
-        mPowerMenuLite = mView.findViewById(R.id.pm_lite);
-        mShowPMLiteButton = showPMLiteButton;
-        mGlobalActionsDialog = globalActionsDialog;
-        mUiEventLogger = uiEventLogger;
     }
 
     @Override
     protected void onInit() {
         super.onInit();
-        mMultiUserSwitchController.init();
+        mQsFooterActionsController.init();
     }
 
     @Override
     protected void onViewAttached() {
-        if (mShowPMLiteButton) {
-            mPowerMenuLite.setVisibility(View.VISIBLE);
-            mPowerMenuLite.setOnClickListener(mSettingsOnClickListener);
-        } else {
-            mPowerMenuLite.setVisibility(View.GONE);
-        }
         mView.addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
-                        mView.updateAnimator(
-                                right - left, mQuickQSPanelController.getNumQuickTiles()));
-        mSettingsButton.setOnClickListener(mSettingsOnClickListener);
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    mView.updateExpansion();
+                    mQsFooterActionsController.updateAnimator(right - left,
+                            mQuickQSPanelController.getNumQuickTiles());
+                }
+        );
+
         mBuildText.setOnLongClickListener(view -> {
             CharSequence buildText = mBuildText.getText();
             if (!TextUtils.isEmpty(buildText)) {
@@ -200,17 +88,8 @@
             }
             return false;
         });
-
-        mEdit.setOnClickListener(view -> {
-            if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                return;
-            }
-            mActivityStarter.postQSRunnableDismissingKeyguard(() ->
-                    mQsPanelController.showEdit(view));
-        });
-
         mQsPanelController.setFooterPageIndicator(mPageIndicator);
-        mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
+        mView.updateEverything();
     }
 
     @Override
@@ -225,38 +104,25 @@
 
     @Override
     public void setExpanded(boolean expanded) {
-        mExpanded = expanded;
-        mView.setExpanded(
-                expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
-    }
-
-    @Override
-    public int getHeight() {
-        return mView.getHeight();
+        mQsFooterActionsController.setExpanded(expanded);
+        mView.setExpanded(expanded);
     }
 
     @Override
     public void setExpansion(float expansion) {
         mView.setExpansion(expansion);
+        mQsFooterActionsController.setExpansion(expansion);
     }
 
     @Override
     public void setListening(boolean listening) {
-        if (mListening == listening) {
-            return;
-        }
-
-        mListening = listening;
-        if (mListening) {
-            mUserInfoController.addCallback(mOnUserInfoChangedListener);
-        } else {
-            mUserInfoController.removeCallback(mOnUserInfoChangedListener);
-        }
+        mQsFooterActionsController.setListening(listening);
     }
 
     @Override
     public void setKeyguardShowing(boolean keyguardShowing) {
         mView.setKeyguardShowing();
+        mQsFooterActionsController.setKeyguardShowing();
     }
 
     /** */
@@ -267,19 +133,7 @@
 
     @Override
     public void disable(int state1, int state2, boolean animate) {
-        mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
-    }
-
-    private void startSettingsActivity() {
-        ActivityLaunchAnimator.Controller animationController =
-                mSettingsButtonContainer != null ? ActivityLaunchAnimator.Controller.fromView(
-                        mSettingsButtonContainer,
-                        InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) : null;
-        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
-                true /* dismissShade */, animationController);
-    }
-
-    private boolean isTunerEnabled() {
-        return mTunerService.isTunerEnabled();
+        mView.disable(state2);
+        mQsFooterActionsController.disable(state2);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index dd81b65..4242e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -37,8 +37,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
@@ -50,6 +52,7 @@
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.LifecycleFragment;
@@ -131,6 +134,8 @@
      */
     private boolean mAnimateNextQsUpdate;
 
+    private DumpManager mDumpManager;
+
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             InjectionInflationController injectionInflater, QSTileHost qsTileHost,
@@ -139,7 +144,7 @@
             @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
             KeyguardBypassController keyguardBypassController,
             QSFragmentComponent.Factory qsComponentFactory,
-            FalsingManager falsingManager) {
+            FalsingManager falsingManager, DumpManager dumpManager) {
         mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
         mInjectionInflater = injectionInflater;
         mCommandQueue = commandQueue;
@@ -152,6 +157,7 @@
         mFalsingManager = falsingManager;
         mBypassController = keyguardBypassController;
         mStatusBarStateController = statusBarStateController;
+        mDumpManager = dumpManager;
     }
 
     @Override
@@ -197,6 +203,7 @@
         mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
         mQSContainerImplController.init();
         mContainer = mQSContainerImplController.getView();
+        mDumpManager.registerDumpable(mContainer.getClass().getName(), mContainer);
 
         mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
         mQSAnimator = qsFragmentComponent.getQSAnimator();
@@ -248,6 +255,7 @@
         mQSCustomizerController.setQs(null);
         mQsDetailDisplayer.setQsPanelController(null);
         mScrollListener = null;
+        mDumpManager.unregisterDumpable(mContainer.getClass().getName());
     }
 
     @Override
@@ -407,6 +415,12 @@
         return mQSPanelController;
     }
 
+    public void setBrightnessMirrorController(
+            BrightnessMirrorController brightnessMirrorController) {
+        mQSPanelController.setBrightnessMirror(brightnessMirrorController);
+        mQuickQSPanelController.setBrightnessMirror(brightnessMirrorController);
+    }
+
     @Override
     public boolean isShowingDetail() {
         return mQSCustomizerController.isCustomizing() || mQSDetail.isShowingDetail();
@@ -496,11 +510,13 @@
                             : headerTranslation);
         }
         int currentHeight = getView().getHeight();
-        mLastHeaderTranslation = headerTranslation;
-        if (expansion == mLastQSExpansion && mLastKeyguardAndExpanded == onKeyguardAndExpanded
-                && mLastViewHeight == currentHeight) {
+        if (expansion == mLastQSExpansion
+                && mLastKeyguardAndExpanded == onKeyguardAndExpanded
+                && mLastViewHeight == currentHeight
+                && mLastHeaderTranslation == headerTranslation) {
             return;
         }
+        mLastHeaderTranslation = headerTranslation;
         mLastQSExpansion = expansion;
         mLastKeyguardAndExpanded = onKeyguardAndExpanded;
         mLastViewHeight = currentHeight;
@@ -520,8 +536,8 @@
         }
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanelController.setRevealExpansion(expansion);
-        mQSPanelController.getTileLayout().setExpansion(expansion);
-        mQuickQSPanelController.getTileLayout().setExpansion(expansion);
+        mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
+        mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
         mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
         if (fullyCollapsed) {
             mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0c65510..28aa884 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -27,12 +27,15 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.widget.RemeasuringLinearLayout;
 import com.android.systemui.R;
@@ -386,13 +389,7 @@
     }
 
     private void switchToParent(View child, ViewGroup parent, int index) {
-        ViewGroup currentParent = (ViewGroup) child.getParent();
-        if (currentParent != parent || currentParent.indexOfChild(child) != index) {
-            if (currentParent != null) {
-                currentParent.removeView(child);
-            }
-            parent.addView(child, index);
-        }
+        switchToParent(child, parent, index, getDumpableTag());
     }
 
     /** Call when orientation has changed and MediaHost needs to be adjusted. */
@@ -739,7 +736,7 @@
         void setListening(boolean listening, UiEventLogger uiEventLogger);
 
         /**
-         * Set the minimum number of rows to show
+         * Sets the minimum number of rows to show
          *
          * @param minRows the minimum.
          */
@@ -748,7 +745,7 @@
         }
 
         /**
-         * Set the max number of columns to show
+         * Sets the max number of columns to show
          *
          * @param maxColumns the maximum
          *
@@ -758,7 +755,10 @@
             return false;
         }
 
-        default void setExpansion(float expansion) {}
+        /**
+         * Sets the expansion value and proposedTranslation to panel.
+         */
+        default void setExpansion(float expansion, float proposedTranslation) {}
 
         int getNumVisibleTiles();
     }
@@ -766,4 +766,29 @@
     interface OnConfigurationChangedListener {
         void onConfigurationChange(Configuration newConfig);
     }
+
+    @VisibleForTesting
+    static void switchToParent(View child, ViewGroup parent, int index, String tag) {
+        if (parent == null) {
+            Log.w(tag, "Trying to move view to null parent",
+                    new IllegalStateException());
+            return;
+        }
+        ViewGroup currentParent = (ViewGroup) child.getParent();
+        if (currentParent != parent) {
+            if (currentParent != null) {
+                currentParent.removeView(child);
+            }
+            parent.addView(child, index);
+            return;
+        }
+        // Same parent, we are just changing indices
+        int currentIndex = parent.indexOfChild(child);
+        if (currentIndex == index) {
+            // We want to be in the same place. Nothing to do here
+            return;
+        }
+        parent.removeView(child);
+        parent.addView(child, index);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index f3d071e..6e09f22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -40,6 +40,7 @@
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.brightness.BrightnessController;
+import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
 import com.android.systemui.settings.brightness.BrightnessSlider;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.tuner.TunerService;
@@ -60,10 +61,9 @@
     private final QSTileRevealController.Factory mQsTileRevealControllerFactory;
     private final FalsingManager mFalsingManager;
     private final BrightnessController mBrightnessController;
-    private final BrightnessSlider.Factory mBrightnessSliderFactory;
     private final BrightnessSlider mBrightnessSlider;
+    private final BrightnessMirrorHandler mBrightnessMirrorHandler;
 
-    private BrightnessMirrorController mBrightnessMirrorController;
     private boolean mGridContentVisible = true;
 
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
@@ -75,14 +75,10 @@
             if (mView.isListening()) {
                 refreshAllTiles();
             }
-            updateBrightnessMirror();
             mView.switchSecurityFooter(mShouldUseSplitNotificationShade);
         }
     };
 
-    private final BrightnessMirrorController.BrightnessMirrorListener mBrightnessMirrorListener =
-            mirror -> updateBrightnessMirror();
-
     private View.OnTouchListener mTileLayoutTouchListener = new View.OnTouchListener() {
         @Override
         public boolean onTouch(View v, MotionEvent event) {
@@ -110,12 +106,12 @@
         mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
         mFalsingManager = falsingManager;
         mQsSecurityFooter.setHostEnvironment(qstileHost);
-        mBrightnessSliderFactory = brightnessSliderFactory;
 
-        mBrightnessSlider = mBrightnessSliderFactory.create(getContext(), mView);
+        mBrightnessSlider = brightnessSliderFactory.create(getContext(), mView);
         mView.setBrightnessView(mBrightnessSlider.getRootView());
 
         mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
+        mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
     }
 
     @Override
@@ -142,9 +138,7 @@
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
         mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
         switchTileLayout(true);
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
-        }
+        mBrightnessMirrorHandler.onQsPanelAttached();
 
         ((PagedTileLayout) mView.getOrCreateTileLayout())
                 .setOnTouchListener(mTileLayoutTouchListener);
@@ -160,9 +154,7 @@
     protected void onViewDetached() {
         mTunerService.removeTunable(mView);
         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener);
-        }
+        mBrightnessMirrorHandler.onQsPanelDettached();
         super.onViewDetached();
     }
 
@@ -196,23 +188,8 @@
         }
     }
 
-    /** */
     public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
-        mBrightnessMirrorController = brightnessMirrorController;
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener);
-        }
-        mBrightnessMirrorController = brightnessMirrorController;
-        if (mBrightnessMirrorController != null) {
-            mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
-        }
-        updateBrightnessMirror();
-    }
-
-    private void updateBrightnessMirror() {
-        if (mBrightnessMirrorController != null) {
-            mBrightnessSlider.setMirrorControllerAndMirror(mBrightnessMirrorController);
-        }
+        mBrightnessMirrorHandler.setController(brightnessMirrorController);
     }
 
     /** Get the QSTileHost this panel uses. */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 756ad99..541ee2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -51,7 +51,6 @@
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -512,33 +511,6 @@
                 }
             }
         }
-        // TODO(b/174753536): Move it into the config file.
-        // Only do the below hacking when at least one of the below tiles exist
-        //   --InternetTile
-        //   --WiFiTile
-        //   --CellularTIle
-        if (tiles.contains("internet") || tiles.contains("wifi") || tiles.contains("cell")) {
-            if (FeatureFlags.isProviderModelSettingEnabled(context)) {
-                if (!tiles.contains("internet")) {
-                    if (tiles.contains("wifi")) {
-                        // Replace the WiFi with Internet, and remove the Cell
-                        tiles.set(tiles.indexOf("wifi"), "internet");
-                        tiles.remove("cell");
-                    } else if (tiles.contains("cell")) {
-                        // Replace the Cell with Internet
-                        tiles.set(tiles.indexOf("cell"), "internet");
-                    }
-                } else {
-                    tiles.remove("wifi");
-                    tiles.remove("cell");
-                }
-            } else {
-                if (tiles.contains("internet")) {
-                    tiles.set(tiles.indexOf("internet"), "wifi");
-                    tiles.add("cell");
-                }
-            }
-        }
         return tiles;
     }
 
@@ -558,14 +530,6 @@
                 && GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
             tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
         }
-        // TODO(b/174753536): Change the config file directly.
-        // Filter out unused tiles from the default QS config.
-        if (FeatureFlags.isProviderModelSettingEnabled(context)) {
-            tiles.remove("cell");
-            tiles.remove("wifi");
-        } else {
-            tiles.remove("internet");
-        }
         return tiles;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
index 7c81abc..14374ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
@@ -19,6 +19,8 @@
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.settings.brightness.BrightnessController
 import com.android.systemui.settings.brightness.BrightnessSlider
+import com.android.systemui.settings.brightness.MirroredBrightnessController
+import com.android.systemui.statusbar.policy.BrightnessMirrorController
 import javax.inject.Inject
 
 /**
@@ -27,7 +29,7 @@
  */
 class QuickQSBrightnessController @VisibleForTesting constructor(
     private val brightnessControllerFactory: () -> BrightnessController
-) {
+) : MirroredBrightnessController {
 
     @Inject constructor(
         brightnessControllerFactory: BrightnessController.Factory,
@@ -42,6 +44,7 @@
 
     private var isListening = false
     private var brightnessController: BrightnessController? = null
+    private var mirrorController: BrightnessMirrorController? = null
 
     fun init(shouldUseSplitNotificationShade: Boolean) {
         refreshVisibility(shouldUseSplitNotificationShade)
@@ -77,6 +80,11 @@
         }
     }
 
+    override fun setMirror(controller: BrightnessMirrorController) {
+        mirrorController = controller
+        mirrorController?.let { brightnessController?.setMirror(it) }
+    }
+
     private fun hideBrightnessSlider() {
         brightnessController?.hideSlider()
     }
@@ -84,11 +92,10 @@
     private fun showBrightnessSlider() {
         if (brightnessController == null) {
             brightnessController = brightnessControllerFactory()
-        }
-        brightnessController?.showSlider()
-        if (!isListening) {
+            mirrorController?.also { brightnessController?.setMirror(it) }
             brightnessController?.registerCallbacks()
             isListening = true
         }
+        brightnessController?.showSlider()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f1c1e12..613e7f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -171,6 +171,8 @@
 
     static class QQSSideLabelTileLayout extends SideLabelTileLayout {
 
+        private boolean mLastSelected;
+
         QQSSideLabelTileLayout(Context context) {
             super(context, null);
             setClipChildren(false);
@@ -216,5 +218,29 @@
                 }
             }
         }
+
+        @Override
+        public void setExpansion(float expansion, float proposedTranslation) {
+            if (expansion > 0f && expansion < 1f) {
+                return;
+            }
+            // The cases we must set select for marquee when QQS/QS collapsed, and QS full expanded.
+            // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+            // point we want them to be selected so the tiles will marquee (but not at other points
+            // of expansion.
+            boolean selected = (expansion == 1f || proposedTranslation < 0f);
+            if (mLastSelected == selected) {
+                return;
+            }
+            // We set it as not important while we change this, so setting each tile as selected
+            // will not cause them to announce themselves until the user has actually selected the
+            // item.
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            for (int i = 0; i < getChildCount(); i++) {
+                getChildAt(i).setSelected(selected);
+            }
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+            mLastSelected = selected;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 74cd50c..8c7a2cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -29,6 +29,8 @@
 import com.android.systemui.qs.customize.QSCustomizerController;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -50,6 +52,7 @@
 
     // brightness is visible only in split shade
     private final QuickQSBrightnessController mBrightnessController;
+    private final BrightnessMirrorHandler mBrightnessMirrorHandler;
 
     @Inject
     QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
@@ -63,6 +66,7 @@
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager);
         mBrightnessController = quickQSBrightnessController;
+        mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
     }
 
     @Override
@@ -78,12 +82,14 @@
     protected void onViewAttached() {
         super.onViewAttached();
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
+        mBrightnessMirrorHandler.onQsPanelAttached();
     }
 
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
+        mBrightnessMirrorHandler.onQsPanelDettached();
     }
 
     @Override
@@ -132,4 +138,8 @@
     public int getNumQuickTiles() {
         return mView.getNumQuickTiles();
     }
+
+    public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
+        mBrightnessMirrorHandler.setController(brightnessMirrorController);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 0004759..a85800b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -35,8 +35,8 @@
 import androidx.annotation.NonNull;
 
 import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.qs.QSDetail.Callback;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
@@ -98,6 +98,9 @@
     private List<String> mRssiIgnoredSlots;
     private boolean mIsSingleCarrier;
 
+    private boolean mHasCenterCutout;
+    private boolean mConfigShowBatteryEstimate;
+
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -138,8 +141,6 @@
 
         updateResources();
 
-        // Don't need to worry about tuner settings for this icon
-        mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
         // QS will always show the estimate, and BatteryMeterView handles the case where
         // it's unavailable or charging
         mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
@@ -208,6 +209,14 @@
         mPrivacyContainer.setLayoutParams(lp);
     }
 
+    private void updateBatteryMode() {
+        if (mConfigShowBatteryEstimate && !mHasCenterCutout) {
+            mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+        } else {
+            mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ON);
+        }
+    }
+
     void updateResources() {
         Resources resources = mContext.getResources();
         // status bar is already displayed out of QS in split shade
@@ -216,6 +225,8 @@
         mStatusIconsView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
         mDatePrivacyView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
 
+        mConfigShowBatteryEstimate = resources.getBoolean(R.bool.config_showBatteryEstimateQSBH);
+
         mRoundedCornerPadding = resources.getDimensionPixelSize(
                 R.dimen.rounded_corner_content_padding);
 
@@ -256,6 +267,7 @@
                 .getDimensionPixelSize(R.dimen.qqs_layout_margin_top);
         mHeaderQsPanel.setLayoutParams(qqsLP);
 
+        updateBatteryMode();
         updateHeadersPadding();
         updateAnimators();
     }
@@ -400,14 +412,14 @@
                 mClockIconsSeparatorLayoutParams.width = 0;
                 setSeparatorVisibility(false);
                 mShowClockIconsSeparator = false;
-                mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
+                mHasCenterCutout = false;
             } else {
                 datePrivacySeparatorLayoutParams.width = topCutout.width();
                 mDatePrivacySeparator.setVisibility(View.VISIBLE);
                 mClockIconsSeparatorLayoutParams.width = topCutout.width();
                 mShowClockIconsSeparator = true;
                 setSeparatorVisibility(mKeyguardExpansionFraction == 0f);
-                mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ON);
+                mHasCenterCutout = true;
             }
         }
         mDatePrivacySeparator.setLayoutParams(datePrivacySeparatorLayoutParams);
@@ -415,6 +427,8 @@
         mCutOutPaddingLeft = padding.first;
         mCutOutPaddingRight = padding.second;
         mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
+
+        updateBatteryMode();
         updateHeadersPadding();
         return super.onApplyWindowInsets(insets);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 1343839..1841e60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -25,9 +25,11 @@
 import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.privacy.OngoingPrivacyChip;
 import com.android.systemui.privacy.PrivacyChipEvent;
@@ -37,7 +39,6 @@
 import com.android.systemui.privacy.logging.PrivacyLogger;
 import com.android.systemui.qs.carrier.QSCarrierGroupController;
 import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
@@ -71,6 +72,7 @@
     private final PrivacyDialogController mPrivacyDialogController;
     private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
     private final FeatureFlags mFeatureFlags;
+    private final BatteryMeterViewController mBatteryMeterViewController;
 
     private final VariableDateViewController mVariableDateViewControllerDateView;
     private final VariableDateViewController mVariableDateViewControllerClockDateView;
@@ -139,7 +141,8 @@
             PrivacyDialogController privacyDialogController,
             QSExpansionPathInterpolator qsExpansionPathInterpolator,
             FeatureFlags featureFlags,
-            VariableDateViewController.Factory variableDateViewControllerFactory) {
+            VariableDateViewController.Factory variableDateViewControllerFactory,
+            BatteryMeterViewController batteryMeterViewController) {
         super(view);
         mPrivacyItemController = privacyItemController;
         mActivityStarter = activityStarter;
@@ -151,6 +154,7 @@
         mPrivacyDialogController = privacyDialogController;
         mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
         mFeatureFlags = featureFlags;
+        mBatteryMeterViewController = batteryMeterViewController;
 
         mQSCarrierGroupController = qsCarrierGroupControllerBuilder
                 .setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
@@ -178,6 +182,14 @@
         mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
         mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
         mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
+
+        // Don't need to worry about tuner settings for this icon
+        mBatteryMeterViewController.ignoreTunerUpdates();
+    }
+
+    @Override
+    protected void onInit() {
+        mBatteryMeterViewController.init();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 67c4d33..953f9fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -40,8 +40,8 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3cb715c..3c2f35b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -41,7 +41,6 @@
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.util.leak.GarbageMonitor;
 
 import java.util.ArrayList;
@@ -63,7 +62,6 @@
     private final Executor mBgExecutor;
     private final Context mContext;
     private final UserTracker mUserTracker;
-    private final FeatureFlags mFeatureFlags;
     private TileStateListener mListener;
 
     private boolean mFinished;
@@ -73,14 +71,12 @@
             Context context,
             UserTracker userTracker,
             @Main Executor mainExecutor,
-            @Background Executor bgExecutor,
-            FeatureFlags featureFlags
+            @Background Executor bgExecutor
     ) {
         mContext = context;
         mMainExecutor = mainExecutor;
         mBgExecutor = bgExecutor;
         mUserTracker = userTracker;
-        mFeatureFlags = featureFlags;
     }
 
     public void setListener(TileStateListener listener) {
@@ -121,19 +117,11 @@
         }
 
         final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
-        // TODO(b/174753536): Move it into the config file.
-        if (mFeatureFlags.isProviderModelSettingEnabled()) {
-            possibleTiles.remove("cell");
-            possibleTiles.remove("wifi");
-        } else {
-            possibleTiles.remove("internet");
-        }
 
         for (String spec : possibleTiles) {
             // Only add current and stock tiles that can be created from QSFactoryImpl.
             // Do not include CustomTile. Those will be created by `addPackageTiles`.
             if (spec.startsWith(CustomTile.PREFIX)) continue;
-            // TODO(b/174753536): Move it into the config file.
             final QSTile tile = host.createTile(spec);
             if (tile == null) {
                 continue;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 6fa44eb..103ac65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -20,7 +20,7 @@
 import android.hardware.display.ColorDisplayManager;
 
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.util.settings.GlobalSettings;
 
 import javax.inject.Named;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 36a1910..2de2d04 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -23,10 +23,12 @@
 import android.view.View;
 
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSContainerImpl;
 import com.android.systemui.qs.QSFooter;
+import com.android.systemui.qs.QSFooterActionsView;
 import com.android.systemui.qs.QSFooterView;
 import com.android.systemui.qs.QSFooterViewController;
 import com.android.systemui.qs.QSFragment;
@@ -109,12 +111,24 @@
 
     /** */
     @Provides
+    static BatteryMeterView providesBatteryMeterView(QuickStatusBarHeader quickStatusBarHeader) {
+        return quickStatusBarHeader.findViewById(R.id.batteryRemainingIcon);
+    }
+
+    /** */
+    @Provides
     static QSFooterView providesQSFooterView(@RootView View view) {
         return view.findViewById(R.id.qs_footer);
     }
 
     /** */
     @Provides
+    static QSFooterActionsView providesQSFooterActionsView(@RootView View view) {
+        return view.findViewById(R.id.qs_footer_actions_container);
+    }
+
+    /** */
+    @Provides
     @QSScope
     static QSFooter providesQSFooter(QSFooterViewController qsFooterViewController) {
         qsFooterViewController.init();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 70685a6..222539d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -195,9 +195,6 @@
             // sibling methods to have special behavior for labelContainer.
             labelContainer.forceUnspecifiedMeasure = true
             secondaryLabel.alpha = 0f
-            // Do not marque in QQS
-            label.ellipsize = TextUtils.TruncateAt.END
-            secondaryLabel.ellipsize = TextUtils.TruncateAt.END
         }
         setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
         setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index f66b722..bc21b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -69,7 +69,7 @@
 
     private var hasControlsApps = AtomicBoolean(false)
 
-    private val icon = ResourceIcon.get(R.drawable.ic_device_light)
+    private val icon = ResourceIcon.get(R.drawable.controls_icon)
 
     private val listingCallback = object : ControlsListingController.ControlsListingCallback {
         override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 44c1b7b..91c81bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -19,7 +19,6 @@
 import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
 import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
@@ -35,10 +34,10 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.settingslib.Utils;
+import com.android.settingslib.wifi.WifiUtils;
 import com.android.systemui.R;
 import com.android.wifitrackerlib.WifiEntry;
 
@@ -98,8 +97,8 @@
         }
 
         return mInternetDialogController.getWifiEntryList().stream()
-                .filter(wifiAp -> wifiAp.getConnectedState()
-                        != WifiEntry.CONNECTED_STATE_CONNECTED)
+                .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
+                        || !wifiEntry.hasInternetAccess()))
                 .limit(getItemCount())
                 .collect(Collectors.toList());
     }
@@ -109,21 +108,21 @@
      * {@link InternetDialog}.
      *
      * Airplane mode is ON (mobile network is gone):
-     *   Return four Wi-Fi's entries if no connected Wi-Fi.
-     *   Return three Wi-Fi's entries if one connected Wi-Fi.
+     *   Return four Wi-Fi's entries if no internet Wi-Fi.
+     *   Return three Wi-Fi's entries if one internet Wi-Fi.
      * Airplane mode is OFF (mobile network is visible):
-     *   Return three Wi-Fi's entries if no connected Wi-Fi.
-     *   Return two Wi-Fi's entries if one connected Wi-Fi.
+     *   Return three Wi-Fi's entries if no internet Wi-Fi.
+     *   Return two Wi-Fi's entries if one internet Wi-Fi.
      *
      * @return The total number of networks.
      */
     @Override
     public int getItemCount() {
-        boolean hasConnectedWifi = mInternetDialogController.getConnectedWifiEntry() != null;
+        final boolean hasInternetWifi = mInternetDialogController.getInternetWifiEntry() != null;
         if (mInternetDialogController.isAirplaneModeEnabled()) {
-            return hasConnectedWifi ? 3 : 4;
+            return hasInternetWifi ? 3 : 4;
         } else {
-            return hasConnectedWifi ? 2 : 3;
+            return hasInternetWifi ? 2 : 3;
         }
     }
 
@@ -142,6 +141,8 @@
         final Context mContext;
         final InternetDialogController mInternetDialogController;
 
+        protected WifiUtils.InternetIconInjector mWifiIconInjector;
+
         InternetViewHolder(View view, InternetDialogController internetDialogController) {
             super(view);
             mContext = view.getContext();
@@ -153,6 +154,7 @@
             mWifiTitleText = view.requireViewById(R.id.wifi_title);
             mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
             mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
+            mWifiIconInjector = mInternetDialogController.getWifiIconInjector();
         }
 
         void onBind(WifiEntry wifiEntry) {
@@ -207,19 +209,17 @@
             mWifiSummaryText.setText(summary);
         }
 
-        Drawable getWifiDrawable(WifiEntry wifiEntry) throws Throwable {
-            Drawable drawable = mContext.getDrawable(
-                    com.android.internal.R.drawable.ic_wifi_signal_0);
-
-            AtomicReference<Drawable> shared = new AtomicReference<>();
-            final @ColorInt int tint = Utils.getColorAttrDefaultColor(mContext,
-                    android.R.attr.colorControlNormal);
-            Drawable signalDrawable = mContext.getDrawable(
-                    Utils.getWifiIconResource(wifiEntry.getLevel()));
-            signalDrawable.setTint(tint);
-            shared.set(signalDrawable);
-            drawable = shared.get();
-            return drawable;
+        Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) throws Throwable {
+            final Drawable drawable = mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(),
+                    wifiEntry.getLevel());
+            if (drawable == null) {
+                return null;
+            }
+            drawable.setTint(
+                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorTertiary));
+            final AtomicReference<Drawable> shared = new AtomicReference<>();
+            shared.set(drawable);
+            return shared.get();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 44c933c..bbcf999 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -91,6 +91,8 @@
     protected WifiManager mWifiManager;
     @VisibleForTesting
     protected View mDialogView;
+    @VisibleForTesting
+    protected WifiEntry mConnectedWifiEntry;
 
     private InternetDialogFactory mInternetDialogFactory;
     private SubscriptionManager mSubscriptionManager;
@@ -101,6 +103,7 @@
     private InternetDialogController mInternetDialogController;
     private TextView mInternetDialogTitle;
     private TextView mInternetDialogSubTitle;
+    private View mDivider;
     private ProgressBar mProgressBar;
     private LinearLayout mInternetListLayout;
     private LinearLayout mConnectedWifListLayout;
@@ -122,7 +125,6 @@
     private Switch mWiFiToggle;
     private Button mDoneButton;
     private Drawable mBackgroundOn;
-    private WifiEntry mConnectedWifiEntry;
     private int mListMaxHeight;
     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private boolean mCanConfigMobileData;
@@ -205,6 +207,7 @@
 
         mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
         mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+        mDivider = mDialogView.requireViewById(R.id.divider);
         mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
         mInternetListLayout = mDialogView.requireViewById(R.id.internet_list);
         mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
@@ -284,14 +287,22 @@
         }
         showProgressBar();
         setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular());
-        setConnectedWifiLayout();
-        boolean isWifiEnabled = mWifiManager.isWifiEnabled();
-        mWiFiToggle.setChecked(isWifiEnabled);
-        int visible = isWifiEnabled ? View.VISIBLE : View.GONE;
-        mWifiRecyclerView.setVisibility(visible);
-        mAdapter.notifyDataSetChanged();
-        mSeeAllLayout.setVisibility(visible);
-        mSpace.setVisibility(isWifiEnabled ? View.GONE : View.VISIBLE);
+
+        final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
+        final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
+        updateWifiToggle(isWifiEnabled, isDeviceLocked);
+        updateConnectedWifi(isWifiEnabled, isDeviceLocked);
+
+        List<WifiEntry> wifiEntryList = mInternetDialogController.getWifiEntryList();
+        final int wifiListVisibility =
+                (isDeviceLocked || wifiEntryList == null || wifiEntryList.size() <= 0)
+                        ? View.GONE : View.VISIBLE;
+        mWifiRecyclerView.setVisibility(wifiListVisibility);
+        if (wifiListVisibility == View.VISIBLE) {
+            mAdapter.notifyDataSetChanged();
+        }
+        mSeeAllLayout.setVisibility(wifiListVisibility);
+        mSpace.setVisibility(wifiListVisibility == View.VISIBLE ? View.GONE : View.VISIBLE);
     }
 
     private void setOnClickListener() {
@@ -338,35 +349,46 @@
                 mMobileSummaryText.setVisibility(View.GONE);
             }
             mSignalIcon.setImageDrawable(getSignalStrengthDrawable());
-            int titleColor = isCellularNetwork ? mContext.getColor(
-                    R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
-                    mContext, android.R.attr.textColorPrimary);
-            int summaryColor = isCellularNetwork ? mContext.getColor(
-                    R.color.connected_network_tertiary_color) : Utils.getColorAttrDefaultColor(
-                    mContext, android.R.attr.textColorTertiary);
-            mMobileTitleText.setTextColor(titleColor);
-            mMobileSummaryText.setTextColor(summaryColor);
+            if (mInternetDialogController.isNightMode()) {
+                int titleColor = isCellularNetwork ? mContext.getColor(
+                        R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                        mContext, android.R.attr.textColorPrimary);
+                int summaryColor = isCellularNetwork ? mContext.getColor(
+                        R.color.connected_network_secondary_color) : Utils.getColorAttrDefaultColor(
+                        mContext, android.R.attr.textColorSecondary);
+
+                mMobileTitleText.setTextColor(titleColor);
+                mMobileSummaryText.setTextColor(summaryColor);
+            }
             mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null);
 
             mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
         }
     }
 
-    private void setConnectedWifiLayout() {
-        if (!mWifiManager.isWifiEnabled()
-                || mInternetDialogController.getConnectedWifiEntry() == null) {
+    private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
+        mWiFiToggle.setChecked(isWifiEnabled);
+        mTurnWifiOnLayout.setBackground(
+                (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
+    }
+
+    private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) {
+        if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) {
             mConnectedWifListLayout.setBackground(null);
             mConnectedWifListLayout.setVisibility(View.GONE);
             return;
         }
         mConnectedWifListLayout.setVisibility(View.VISIBLE);
-        mConnectedWifiTitleText.setText(getConnectedWifiTitle());
-        mConnectedWifiSummaryText.setText(getConnectedWifiSummary());
-        mConnectedWifiIcon.setImageDrawable(getConnectedWifiDrawable());
-        mConnectedWifiTitleText.setTextColor(
-                mContext.getColor(R.color.connected_network_primary_color));
-        mConnectedWifiSummaryText.setTextColor(
-                mContext.getColor(R.color.connected_network_tertiary_color));
+        mConnectedWifiTitleText.setText(mInternetDialogController.getInternetWifiTitle());
+        mConnectedWifiSummaryText.setText(mInternetDialogController.getInternetWifiSummary());
+        mConnectedWifiIcon.setImageDrawable(
+                mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
+        if (mInternetDialogController.isNightMode()) {
+            mConnectedWifiTitleText.setTextColor(
+                    mContext.getColor(R.color.connected_network_primary_color));
+            mConnectedWifiSummaryText.setTextColor(
+                    mContext.getColor(R.color.connected_network_secondary_color));
+        }
         mWifiSettingsIcon.setColorFilter(
                 mContext.getColor(R.color.connected_network_primary_color));
         mConnectedWifListLayout.setBackground(mBackgroundOn);
@@ -389,15 +411,6 @@
                 mIsProgressBarVisible && !mIsSearchingHidden);
     }
 
-    private Drawable getConnectedWifiDrawable() {
-        try {
-            return mInternetDialogController.getWifiConnectedDrawable(mConnectedWifiEntry);
-        } catch (Throwable e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
     private Drawable getSignalStrengthDrawable() {
         return mInternetDialogController.getSignalStrengthDrawable();
     }
@@ -410,16 +423,9 @@
         return mInternetDialogController.getMobileNetworkSummary();
     }
 
-    String getConnectedWifiTitle() {
-        return mInternetDialogController.getConnectedWifiTitle();
-    }
-
-    String getConnectedWifiSummary() {
-        return mInternetDialogController.getConnectedWifiSummary();
-    }
-
     protected void showProgressBar() {
-        if (mWifiManager == null || !mWifiManager.isWifiEnabled()) {
+        if (mWifiManager == null || !mWifiManager.isWifiEnabled()
+                || mInternetDialogController.isDeviceLocked()) {
             setProgressBarVisible(false);
             return;
         }
@@ -438,7 +444,8 @@
             mIsProgressBarVisible = true;
         }
         mIsProgressBarVisible = visible;
-        mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.INVISIBLE);
+        mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.GONE);
+        mDivider.setVisibility(mIsProgressBarVisible ? View.GONE : View.VISIBLE);
         mInternetDialogSubTitle.setText(getSubtitleText());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 13c5763..ed32730 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -19,11 +19,11 @@
 import static com.android.settingslib.mobile.MobileMappings.getIconKey;
 import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
 
-import android.annotation.ColorInt;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -67,6 +67,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -97,6 +98,8 @@
     private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off;
     private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT =
             R.string.tap_a_network_to_connect;
+    private static final int SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS =
+            R.string.unlock_to_view_networks;
     private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS =
             R.string.wifi_empty_list_wifi_on;
     private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE =
@@ -134,6 +137,11 @@
     protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
     @VisibleForTesting
     protected InternetTelephonyCallback mInternetTelephonyCallback;
+    @VisibleForTesting
+    protected WifiUtils.InternetIconInjector mWifiIconInjector;
+
+    @VisibleForTesting
+    KeyguardStateController mKeyguardStateController;
 
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -159,7 +167,7 @@
             @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
             @Main Handler handler, @Main Executor mainExecutor,
             BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor,
-            GlobalSettings globalSettings) {
+            GlobalSettings globalSettings, KeyguardStateController keyguardStateController) {
         if (DEBUG) {
             Log.d(TAG, "Init InternetDialogController");
         }
@@ -173,6 +181,7 @@
         mSubscriptionManager = subscriptionManager;
         mBroadcastDispatcher = broadcastDispatcher;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mKeyguardStateController = keyguardStateController;
         mConnectionStateFilter = new IntentFilter();
         mConnectionStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         mConnectionStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
@@ -181,6 +190,7 @@
         mActivityStarter = starter;
         mAccessPointController = accessPointController;
         mConfig = MobileMappings.Config.readConfig(mContext);
+        mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
     }
 
     void onStart(@NonNull InternetDialogCallback callback) {
@@ -269,6 +279,15 @@
             return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF);
         }
 
+        if (isDeviceLocked()) {
+            // When the device is locked.
+            //   Sub-Title: Unlock to view networks
+            if (DEBUG) {
+                Log.d(TAG, "The device is locked.");
+            }
+            return mContext.getText(SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS);
+        }
+
         final List<ScanResult> wifiList = mWifiManager.getScanResults();
         if (wifiList != null && wifiList.size() != 0) {
             return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
@@ -315,17 +334,21 @@
         return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
     }
 
-    Drawable getWifiConnectedDrawable(WifiEntry wifiEntry) throws Throwable {
-        final @ColorInt int tint;
-        tint = Utils.getColorAttrDefaultColor(mContext,
-                com.android.internal.R.attr.colorAccentPrimaryVariant);
-        final Drawable drawable = mContext.getDrawable(
-                com.android.settingslib.Utils.getWifiIconResource(wifiEntry.getLevel()));
-        drawable.setTint(tint);
-
+    Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) {
+        final Drawable drawable =
+                mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
+        if (drawable == null) {
+            return null;
+        }
+        drawable.setTint(mContext.getColor(R.color.connected_network_primary_color));
         return drawable;
     }
 
+    boolean isNightMode() {
+        return (mContext.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+    }
+
     Drawable getSignalStrengthDrawable() {
         Drawable drawable = mContext.getDrawable(
                 R.drawable.ic_signal_strength_zero_bar_no_internet);
@@ -343,13 +366,9 @@
                 drawable = shared.get();
             }
 
-            drawable.setTint(
-                    Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal));
-            if (activeNetworkIsCellular()) {
-                drawable.setTint(Utils.getColorAttrDefaultColor(mContext,
-                        com.android.internal.R.attr.colorAccentPrimaryVariant));
-            }
-
+            drawable.setTint(activeNetworkIsCellular() ? mContext.getColor(
+                    R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+                    mContext, android.R.attr.textColorTertiary));
         } catch (Throwable e) {
             e.printStackTrace();
         }
@@ -396,7 +415,7 @@
         // Set the signal strength icon at the bottom right
         icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT);
         icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize);
-        icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal));
+        icons.setTintList(Utils.getColorAttr(context, android.R.attr.textColorTertiary));
         return icons;
     }
 
@@ -530,24 +549,24 @@
         return summary;
     }
 
-    String getConnectedWifiTitle() {
-        if (getConnectedWifiEntry() == null) {
+    String getInternetWifiTitle() {
+        if (getInternetWifiEntry() == null) {
             if (DEBUG) {
                 Log.d(TAG, "connected entry is null");
             }
             return "";
         }
-        return getConnectedWifiEntry().getTitle();
+        return getInternetWifiEntry().getTitle();
     }
 
-    String getConnectedWifiSummary() {
-        if (getConnectedWifiEntry() == null) {
+    String getInternetWifiSummary() {
+        if (getInternetWifiEntry() == null) {
             if (DEBUG) {
                 Log.d(TAG, "connected entry is null");
             }
             return "";
         }
-        return getConnectedWifiEntry().getSummary(false);
+        return getInternetWifiEntry().getSummary(false);
     }
 
     void launchNetworkSetting() {
@@ -575,7 +594,11 @@
         return mWifiEntry;
     }
 
-    WifiEntry getConnectedWifiEntry() {
+    WifiEntry getInternetWifiEntry() {
+        if (mConnectedEntry == null || !mConnectedEntry.isDefaultNetwork()
+                || !mConnectedEntry.hasInternetAccess()) {
+            return null;
+        }
         return mConnectedEntry;
     }
 
@@ -677,6 +700,10 @@
                 && serviceState.getState() == serviceState.STATE_IN_SERVICE;
     }
 
+    public boolean isDeviceLocked() {
+        return !mKeyguardStateController.isUnlocked();
+    }
+
     boolean activeNetworkIsCellular() {
         if (mConnectivityManager == null) {
             if (DEBUG) {
@@ -775,7 +802,7 @@
             mConnectedEntry = null;
         }
 
-        mCallback.onAccessPointsChanged(mWifiEntry, mConnectedEntry);
+        mCallback.onAccessPointsChanged(mWifiEntry, getInternetWifiEntry());
     }
 
     @Override
@@ -878,6 +905,10 @@
         }
     }
 
+    public WifiUtils.InternetIconInjector getWifiIconInjector() {
+        return mWifiIconInjector;
+    }
+
     interface InternetDialogCallback {
 
         void onRefreshCarrierInfo();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index eb72296..ad7c522 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -427,6 +427,19 @@
         }
     };
 
+    private final BroadcastReceiver mDebugAnyPackageChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String[] stringArrayExtra = intent.getStringArrayExtra(
+                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+            Log.e("b/188806432", intent.toString()
+                    + (stringArrayExtra != null
+                            ? ", EXTRA_CHANGED_COMPONENT_NAME_LIST: " + String.join(", ",
+                            stringArrayExtra)
+                            : ""));
+        }
+    };
+
     private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -566,6 +579,13 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
 
+        // b/188806432
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addDataScheme("package");
+        filter.addDataSchemeSpecificPart("", PatternMatcher.PATTERN_PREFIX);
+        mContext.registerReceiver(mDebugAnyPackageChangedReceiver, filter);
+
         // Listen for status bar state changes
         statusBarWinController.registerCallback(mStatusBarWindowCallback);
         mScreenshotHelper = new ScreenshotHelper(context);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index ce6e469..93e5021 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -45,9 +45,12 @@
 import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Background;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.concurrent.Executor;
+
 import javax.inject.Inject;
 
 /**
@@ -63,6 +66,8 @@
 
     private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
 
+    private final Executor mBgExecutor;
+
     /**
      * Represents the connection to a target window and provides a mechanism for requesting tiles.
      */
@@ -155,8 +160,10 @@
     private IBinder mHostWindowToken;
 
     @Inject
-    public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) {
+    public ScrollCaptureClient(IWindowManager windowManagerService,
+            @Background Executor bgExecutor, @UiContext Context context) {
         requireNonNull(context.getDisplay(), "context must be associated with a Display!");
+        mBgExecutor = bgExecutor;
         mWindowManagerService = windowManagerService;
     }
 
@@ -220,21 +227,25 @@
                 return "";
             }
             SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(),
-                    response.getBoundsInWindow(), maxPages);
+                    response.getBoundsInWindow(), maxPages, mBgExecutor);
             session.start(completer);
             return "IScrollCaptureCallbacks#onCaptureStarted";
         });
     }
 
     private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session,
-            IBinder.DeathRecipient {
+            IBinder.DeathRecipient, ImageReader.OnImageAvailableListener {
 
         private IScrollCaptureConnection mConnection;
+        private final Executor mBgExecutor;
+        private final Object mLock = new Object();
 
         private ImageReader mReader;
         private final int mTileHeight;
         private final int mTileWidth;
         private Rect mRequestRect;
+        private Rect mCapturedArea;
+        private Image mCapturedImage;
         private boolean mStarted;
         private final int mTargetHeight;
 
@@ -247,7 +258,8 @@
         private Completer<Void> mEndCompleter;
 
         private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds,
-                Rect boundsInWindow, float maxPages) throws RemoteException {
+                Rect boundsInWindow, float maxPages, Executor bgExecutor)
+                throws RemoteException {
             mConnection = requireNonNull(connection);
             mConnection.asBinder().linkToDeath(SessionWrapper.this, 0);
             mWindowBounds = requireNonNull(windowBounds);
@@ -259,7 +271,7 @@
             mTileWidth = mBoundsInWindow.width();
             mTileHeight = pxPerTile / mBoundsInWindow.width();
             mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
-
+            mBgExecutor = bgExecutor;
             if (DEBUG_SCROLL) {
                 Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
                 Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
@@ -289,6 +301,7 @@
             mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
                     MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
             mStartCompleter = completer;
+            mReader.setOnImageAvailableListenerWithExecutor(this, mBgExecutor);
             try {
                 mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
                 completer.addCancellationListener(() -> {
@@ -339,9 +352,34 @@
 
         @BinderThread
         @Override
-        public void onImageRequestCompleted(int flags, Rect contentArea) {
-            Image image = mReader.acquireLatestImage();
-            mTileRequestCompleter.set(new CaptureResult(image, mRequestRect, contentArea));
+        public void onImageRequestCompleted(int flagsUnused, Rect contentArea) {
+            synchronized (mLock) {
+                mCapturedArea = contentArea;
+                if (mCapturedImage != null || (mCapturedArea == null || mCapturedArea.isEmpty())) {
+                    completeCaptureRequest();
+                }
+            }
+        }
+
+        /** @see ImageReader.OnImageAvailableListener */
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            synchronized (mLock) {
+                mCapturedImage = mReader.acquireLatestImage();
+                if (mCapturedArea != null) {
+                    completeCaptureRequest();
+                }
+            }
+        }
+
+        /** Produces a result for the caller as soon as both asynchronous results are received. */
+        private void completeCaptureRequest() {
+            CaptureResult result =
+                    new CaptureResult(mCapturedImage, mRequestRect, mCapturedArea);
+            mCapturedImage = null;
+            mRequestRect = null;
+            mCapturedArea = null;
+            mTileRequestCompleter.set(result);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 9e4a355..acc6ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -30,7 +30,6 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -47,15 +46,16 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.systemui.Dependency;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 
 import java.util.ArrayList;
 
 import javax.inject.Inject;
 
-public class BrightnessController implements ToggleSlider.Listener {
+public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController {
     private static final String TAG = "StatusBar.BrightnessController";
     private static final int SLIDER_ANIMATION_DURATION = 3000;
 
@@ -109,6 +109,11 @@
 
     private ValueAnimator mSliderAnimator;
 
+    @Override
+    public void setMirror(BrightnessMirrorController controller) {
+        mControl.setMirrorControllerAndMirror(controller);
+    }
+
     public interface BrightnessStateChangeCallback {
         /** Indicates that some of the brightness settings have changed */
         void onBrightnessLevelChanged();
@@ -282,12 +287,15 @@
         }
     };
 
-    public BrightnessController(Context context, ToggleSlider control,
-            BroadcastDispatcher broadcastDispatcher) {
+    public BrightnessController(
+            Context context,
+            ToggleSlider control,
+            BroadcastDispatcher broadcastDispatcher,
+            @Background Handler bgHandler) {
         mContext = context;
         mControl = control;
         mControl.setMax(GAMMA_SPACE_MAX);
-        mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
+        mBackgroundHandler = bgHandler;
         mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
@@ -354,10 +362,9 @@
                 convertGammaToLinearFloat(value, minBacklight, maxBacklight),
                 maxBacklight);
         if (stopTracking) {
-            // Log brightness as a value between 0-1000 directly correlated to brightnesses 0-1.0
+            // TODO(brightnessfloat): change to use float value instead.
             MetricsLogger.action(mContext, metric,
-                    Math.round(MathUtils.constrainedMap(0, 1000, PowerManager.BRIGHTNESS_MIN,
-                        PowerManager.BRIGHTNESS_MAX, valFloat)));
+                    BrightnessSynchronizer.brightnessFloatToInt(valFloat));
 
         }
         setBrightness(valFloat);
@@ -459,16 +466,25 @@
     public static class Factory {
         private final Context mContext;
         private final BroadcastDispatcher mBroadcastDispatcher;
+        private final Handler mBackgroundHandler;
 
         @Inject
-        public Factory(Context context, BroadcastDispatcher broadcastDispatcher) {
+        public Factory(
+                Context context,
+                BroadcastDispatcher broadcastDispatcher,
+                @Background Handler bgHandler) {
             mContext = context;
             mBroadcastDispatcher = broadcastDispatcher;
+            mBackgroundHandler = bgHandler;
         }
 
         /** Create a {@link BrightnessController} */
         public BrightnessController create(ToggleSlider toggleSlider) {
-            return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher);
+            return new BrightnessController(
+                    mContext,
+                    toggleSlider,
+                    mBroadcastDispatcher,
+                    mBackgroundHandler);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 0f97e43..8fc831a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -21,6 +21,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.os.Handler;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.View;
@@ -32,6 +33,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
 
 import javax.inject.Inject;
 
@@ -41,13 +43,16 @@
     private BrightnessController mBrightnessController;
     private final BrightnessSlider.Factory mToggleSliderFactory;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final Handler mBackgroundHandler;
 
     @Inject
     public BrightnessDialog(
             BroadcastDispatcher broadcastDispatcher,
-            BrightnessSlider.Factory factory) {
+            BrightnessSlider.Factory factory,
+            @Background Handler bgHandler) {
         mBroadcastDispatcher = broadcastDispatcher;
         mToggleSliderFactory = factory;
+        mBackgroundHandler = bgHandler;
     }
 
 
@@ -76,7 +81,8 @@
         controller.init();
         frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
 
-        mBrightnessController = new BrightnessController(this, controller, mBroadcastDispatcher);
+        mBrightnessController = new BrightnessController(
+                this, controller, mBroadcastDispatcher, mBackgroundHandler);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt
new file mode 100644
index 0000000..51aa339
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.settings.brightness
+
+import com.android.systemui.statusbar.policy.BrightnessMirrorController
+import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener
+
+class BrightnessMirrorHandler(private val brightnessController: MirroredBrightnessController) {
+
+    private var mirrorController: BrightnessMirrorController? = null
+
+    private val brightnessMirrorListener = BrightnessMirrorListener { updateBrightnessMirror() }
+
+    fun onQsPanelAttached() {
+        mirrorController?.addCallback(brightnessMirrorListener)
+    }
+
+    fun onQsPanelDettached() {
+        mirrorController?.removeCallback(brightnessMirrorListener)
+    }
+
+    fun setController(controller: BrightnessMirrorController) {
+        mirrorController?.removeCallback(brightnessMirrorListener)
+        mirrorController = controller
+        mirrorController?.addCallback(brightnessMirrorListener)
+        updateBrightnessMirror()
+    }
+
+    private fun updateBrightnessMirror() {
+        mirrorController?.let { brightnessController.setMirror(it) }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
index 896106a..b0e320a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
@@ -140,13 +140,7 @@
     @Override
     public void setMirrorControllerAndMirror(BrightnessMirrorController c) {
         mMirrorController = c;
-        if (c != null) {
-            setMirror(c.getToggleSlider());
-        } else {
-            // If there's no mirror, we may be the ones dispatching, events but we should not mirror
-            // them
-            mView.setOnDispatchTouchEventListener(null);
-        }
+        setMirror(c.getToggleSlider());
     }
 
     @Override
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
similarity index 61%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
index c7c2ad8..8d857de 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
@@ -11,9 +11,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
 
-package com.android.internal.inputmethod;
+package com.android.systemui.settings.brightness
 
-parcelable InputConnectionCommand;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController
+
+/**
+ * Indicates controller that has brightness slider and uses [BrightnessMirrorController]
+ */
+interface MirroredBrightnessController {
+    fun setMirror(controller: BrightnessMirrorController)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
deleted file mode 100644
index b76cebf..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.FeatureFlagUtils;
-
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlagReader;
-
-import javax.inject.Inject;
-
-/**
- * Class to manage simple DeviceConfig-based feature flags.
- *
- * See {@link FeatureFlagReader} for instructions on defining and flipping flags.
- */
-@SysUISingleton
-public class FeatureFlags {
-    private final FeatureFlagReader mFlagReader;
-    private final Context mContext;
-
-    @Inject
-    public FeatureFlags(FeatureFlagReader flagReader, Context context) {
-        mFlagReader = flagReader;
-        mContext = context;
-    }
-
-    public boolean isNewNotifPipelineEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2);
-    }
-
-    public boolean isNewNotifPipelineRenderingEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering);
-    }
-
-    public boolean isKeyguardLayoutEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
-    }
-
-    public boolean useNewLockscreenAnimations() {
-        return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
-    }
-
-    public boolean isPeopleTileEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_conversations);
-    }
-
-    public boolean isMonetEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_monet);
-    }
-
-    public boolean isPMLiteEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_pm_lite);
-    }
-
-    public boolean isChargingRippleEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
-    }
-
-    public boolean isOngoingCallStatusBarChipEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip);
-    }
-
-    public boolean isSmartspaceEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_smartspace);
-    }
-
-    public boolean isSmartspaceDedupingEnabled() {
-        return isSmartspaceEnabled() && mFlagReader.isEnabled(R.bool.flag_smartspace_deduping);
-    }
-
-    public boolean isNewKeyguardSwipeAnimationEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_new_unlock_swipe_animation);
-    }
-
-    public boolean isSmartSpaceSharedElementTransitionEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_smartspace_shared_element_transition);
-    }
-
-    /** Whether or not to use the provider model behavior for the status bar icons */
-    public boolean isCombinedStatusBarSignalIconsEnabled() {
-        return mFlagReader.isEnabled(R.bool.flag_combined_status_bar_signal_icons);
-    }
-
-    /** System setting for provider model behavior */
-    public boolean isProviderModelSettingEnabled() {
-        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
-    }
-
-    /** static method for the system setting */
-    public static boolean isProviderModelSettingEnabled(Context context) {
-        return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index acfd998..8e6cf36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -17,14 +17,10 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.AttributeSet;
-import android.view.DisplayCutout;
 import android.view.View;
 import android.widget.TextView;
 
@@ -42,22 +38,14 @@
 public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
     private static final String HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE =
             "heads_up_status_bar_view_super_parcelable";
-    private static final String FIRST_LAYOUT = "first_layout";
     private static final String VISIBILITY = "visibility";
     private static final String ALPHA = "alpha";
-    private int mAbsoluteStartPadding;
-    private int mEndMargin;
+    private final Rect mLayoutedIconRect = new Rect();
+    private final int[] mTmpPosition = new int[2];
+    private final Rect mIconDrawingRect = new Rect();
     private View mIconPlaceholder;
     private TextView mTextView;
     private NotificationEntry mShowingEntry;
-    private Rect mLayoutedIconRect = new Rect();
-    private int[] mTmpPosition = new int[2];
-    private boolean mFirstLayout = true;
-    private int mMaxWidth;
-    private int mSysWinInset;
-    private int mCutOutInset;
-    private Rect mIconDrawingRect = new Rect();
-    private Point mDisplaySize;
     private Runnable mOnDrawingRectChangedListener;
 
     public HeadsUpStatusBarView(Context context) {
@@ -75,40 +63,6 @@
     public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        Resources res = getResources();
-        mAbsoluteStartPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings)
-            + res.getDimensionPixelSize(
-                    com.android.internal.R.dimen.notification_content_margin_start);
-        mEndMargin = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_margin_end);
-        setPaddingRelative(mAbsoluteStartPadding, 0, mEndMargin, 0);
-        updateMaxWidth();
-    }
-
-    private void updateMaxWidth() {
-        int maxWidth = getResources().getDimensionPixelSize(R.dimen.qs_panel_width);
-        if (maxWidth != mMaxWidth) {
-            // maxWidth doesn't work with fill_parent, let's manually make it at most as big as the
-            // notification panel
-            mMaxWidth = maxWidth;
-            requestLayout();
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mMaxWidth > 0) {
-            int newSize = Math.min(MeasureSpec.getSize(widthMeasureSpec), mMaxWidth);
-            widthMeasureSpec = MeasureSpec.makeMeasureSpec(newSize,
-                    MeasureSpec.getMode(widthMeasureSpec));
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        updateMaxWidth();
     }
 
     @Override
@@ -116,7 +70,6 @@
         Bundle bundle = new Bundle();
         bundle.putParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE,
                 super.onSaveInstanceState());
-        bundle.putBoolean(FIRST_LAYOUT, mFirstLayout);
         bundle.putInt(VISIBILITY, getVisibility());
         bundle.putFloat(ALPHA, getAlpha());
 
@@ -125,7 +78,7 @@
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        if (state == null || !(state instanceof Bundle)) {
+        if (!(state instanceof Bundle)) {
             super.onRestoreInstanceState(state);
             return;
         }
@@ -133,7 +86,6 @@
         Bundle bundle = (Bundle) state;
         Parcelable superState = bundle.getParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE);
         super.onRestoreInstanceState(superState);
-        mFirstLayout = bundle.getBoolean(FIRST_LAYOUT, true);
         if (bundle.containsKey(VISIBILITY)) {
             setVisibility(bundle.getInt(VISIBILITY));
         }
@@ -185,70 +137,22 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         mIconPlaceholder.getLocationOnScreen(mTmpPosition);
-        int left = (int) (mTmpPosition[0] - getTranslationX());
+        int left = mTmpPosition[0];
         int top = mTmpPosition[1];
         int right = left + mIconPlaceholder.getWidth();
         int bottom = top + mIconPlaceholder.getHeight();
         mLayoutedIconRect.set(left, top, right, bottom);
         updateDrawingRect();
-        int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
-        boolean isRtl = isLayoutRtl();
-        int start = isRtl ? (mDisplaySize.x - right) : left;
-        if (start != targetPadding) {
-            int newPadding = targetPadding - start + getPaddingStart();
-            setPaddingRelative(newPadding, 0, mEndMargin, 0);
-        }
-        if (mFirstLayout) {
-            // we need to do the padding calculation in the first frame, so the layout specified
-            // our visibility to be INVISIBLE in the beginning. let's correct that and set it
-            // to GONE.
-            setVisibility(GONE);
-            mFirstLayout = false;
-        }
-    }
-
-    /** In order to do UI alignment, this view will be notified by
-     * {@link com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout}.
-     * After scroller laid out, the scroller will tell this view about scroller's getX()
-     * @param translationX how to translate the horizontal position
-     */
-    public void setPanelTranslation(float translationX) {
-        setTranslationX(translationX);
-        updateDrawingRect();
     }
 
     private void updateDrawingRect() {
         float oldLeft = mIconDrawingRect.left;
         mIconDrawingRect.set(mLayoutedIconRect);
-        mIconDrawingRect.offset((int) getTranslationX(), 0);
         if (oldLeft != mIconDrawingRect.left && mOnDrawingRectChangedListener != null) {
             mOnDrawingRectChangedListener.run();
         }
     }
 
-    @Override
-    protected boolean fitSystemWindows(Rect insets) {
-        boolean isRtl = isLayoutRtl();
-        mSysWinInset = isRtl ? insets.right : insets.left;
-        DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
-        mCutOutInset = (displayCutout != null)
-                ? (isRtl ? displayCutout.getSafeInsetRight() : displayCutout.getSafeInsetLeft())
-                : 0;
-
-        getDisplaySize();
-
-        // For Double Cut Out mode, the System window navigation bar is at the right
-        // side of the left cut out. In this condition, mSysWinInset include the left cut
-        // out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
-        // The navigation bar is at the left side of the right cut out and include the
-        // right cut out width.
-        if (mSysWinInset != 0) {
-            mCutOutInset = 0;
-        }
-
-        return super.fitSystemWindows(insets);
-    }
-
     public NotificationEntry getShowingEntry() {
         return mShowingEntry;
     }
@@ -264,17 +168,4 @@
     public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
         mOnDrawingRectChangedListener = onDrawingRectChangedListener;
     }
-
-    private void getDisplaySize() {
-        if (mDisplaySize == null) {
-            mDisplaySize = new Point();
-        }
-        getDisplay().getRealSize(mDisplaySize);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        getDisplaySize();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 92922b6..503b5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -821,6 +821,20 @@
         }
     }
 
+    private void showTryFingerprintMsg() {
+        if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+            // if udfps available, there will always be a tappable affordance to unlock
+            // For example, the lock icon
+            if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
+                showTransientIndication(R.string.keyguard_unlock_press);
+            } else {
+                showTransientIndication(R.string.keyguard_face_failed_use_fp);
+            }
+        } else {
+            showTransientIndication(R.string.keyguard_try_fingerprint);
+        }
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardIndicationController:");
         pw.println("  mInitialTextColorState: " + mInitialTextColorState);
@@ -891,7 +905,7 @@
                 return;
             }
 
-            boolean showSwipeToUnlock =
+            boolean showActionToUnlock =
                     msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
@@ -899,13 +913,11 @@
             } else if (mKeyguardUpdateMonitor.isScreenOn()) {
                 if (biometricSourceType == BiometricSourceType.FACE
                         && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
-                    // suggest trying fingerprint
-                    showTransientIndication(R.string.keyguard_try_fingerprint);
+                    showTryFingerprintMsg();
                     return;
                 }
-                showTransientIndication(helpString, false /* isError */, showSwipeToUnlock);
-            }
-            if (showSwipeToUnlock) {
+                showTransientIndication(helpString, false /* isError */, showActionToUnlock);
+            } else if (showActionToUnlock) {
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
                         TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             }
@@ -921,8 +933,7 @@
                     && shouldSuppressFaceMsgAndShowTryFingerprintMsg()
                     && !mStatusBarKeyguardViewManager.isBouncerShowing()
                     && mKeyguardUpdateMonitor.isScreenOn()) {
-                // suggest trying fingerprint
-                showTransientIndication(R.string.keyguard_try_fingerprint);
+                showTryFingerprintMsg();
                 return;
             }
             if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -931,11 +942,10 @@
                 if (!mStatusBarKeyguardViewManager.isBouncerShowing()
                         && mKeyguardUpdateMonitor.isUdfpsEnrolled()
                         && mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
-                    // suggest trying fingerprint
-                    showTransientIndication(R.string.keyguard_try_fingerprint);
+                    showTryFingerprintMsg();
                 } else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
                     mStatusBarKeyguardViewManager.showBouncerMessage(
-                            mContext.getResources().getString(R.string.keyguard_try_fingerprint),
+                            mContext.getResources().getString(R.string.keyguard_unlock_press),
                             mInitialTextColorState
                     );
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 8969b4d..36d2d86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -52,6 +52,7 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaData;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.SmartspaceMediaData;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index db553e4..002c9c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -178,7 +178,8 @@
                 blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
         var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
                 normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
-        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
+        val qsExpandedRatio = qsPanelExpansion * shadeExpansion
+        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
         var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 22bbb81b..d74297e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -29,7 +29,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.Utils
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.policy.BatteryController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index a05e950..f2cf93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -24,13 +24,13 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.carrier.QSCarrierGroupController;
 import com.android.systemui.statusbar.ActionClickLogger;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.MediaArtworkProcessor;
 import com.android.systemui.statusbar.NotificationClickNotifier;
 import com.android.systemui.statusbar.NotificationListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 71546ae..fdbe728 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -31,6 +31,8 @@
 import android.os.UserHandle
 import android.provider.Settings
 import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
 import android.view.ViewGroup
 import com.android.settingslib.Utils
 import com.android.systemui.R
@@ -43,15 +45,22 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.AnimatableProperty
+import com.android.systemui.statusbar.notification.PropertyAnimator
+import com.android.systemui.statusbar.notification.stack.AnimationProperties
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.Execution
 import com.android.systemui.util.settings.SecureSettings
-import java.lang.RuntimeException
 import java.util.Optional
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
+private val ANIMATION_PROPERTIES = AnimationProperties()
+        .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD.toLong())
+
 /**
  * Controller for managing the smartspace view on the lockscreen
  */
@@ -72,10 +81,15 @@
     @Main private val handler: Handler,
     optionalPlugin: Optional<BcSmartspaceDataPlugin>
 ) {
+
+    var splitShadeContainer: ViewGroup? = null
+    private var singlePaneContainer: ViewGroup? = null
+
     private var session: SmartspaceSession? = null
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
     private lateinit var smartspaceView: SmartspaceView
 
+    // smartspace casted to View
     lateinit var view: View
         private set
 
@@ -83,12 +97,60 @@
     private var showSensitiveContentForManagedUser = false
     private var managedUserHandle: UserHandle? = null
 
-    fun isEnabled(): Boolean {
+    private var isAod = false
+    private var isSplitShade = false
+
+    fun isSmartspaceEnabled(): Boolean {
         execution.assertIsMainThread()
 
         return featureFlags.isSmartspaceEnabled && plugin != null
     }
 
+    fun setKeyguardStatusContainer(container: ViewGroup) {
+        singlePaneContainer = container
+        // reattach smartspace if necessary as this might be a new container
+        updateSmartSpaceContainer()
+    }
+
+    fun onSplitShadeChanged(splitShade: Boolean) {
+        isSplitShade = splitShade
+        updateSmartSpaceContainer()
+    }
+
+    private fun updateSmartSpaceContainer() {
+        if (!isSmartspaceEnabled()) return
+        // in AOD we always want to show smartspace on the left i.e. in singlePaneContainer
+        if (isSplitShade && !isAod) {
+            switchContainerVisibility(
+                    newParent = splitShadeContainer,
+                    oldParent = singlePaneContainer)
+        } else {
+            switchContainerVisibility(
+                    newParent = singlePaneContainer,
+                    oldParent = splitShadeContainer)
+        }
+        requestSmartspaceUpdate()
+    }
+
+    private fun switchContainerVisibility(newParent: ViewGroup?, oldParent: ViewGroup?) {
+        // it might be the case that smartspace was already attached and we just needed to update
+        // visibility, e.g. going from lockscreen -> unlocked -> lockscreen
+        if (newParent?.childCount == 0) {
+            oldParent?.removeAllViews()
+            newParent.addView(buildAndConnectView(newParent))
+        }
+        oldParent?.visibility = GONE
+        newParent?.visibility = VISIBLE
+    }
+
+    fun setSplitShadeSmartspaceAlpha(alpha: Float) {
+        // the other container's alpha is modified as a part of keyguard status view, so we don't
+        // have to do that here
+        if (splitShadeContainer?.visibility == VISIBLE) {
+            splitShadeContainer?.alpha = alpha
+        }
+    }
+
     /**
      * Constructs the smartspace view and connects it to the smartspace service. Subsequent calls
      * are idempotent until [disconnect] is called.
@@ -96,7 +158,7 @@
     fun buildAndConnectView(parent: ViewGroup): View {
         execution.assertIsMainThread()
 
-        if (!isEnabled()) {
+        if (!isSmartspaceEnabled()) {
             throw RuntimeException("Cannot build view when not enabled")
         }
 
@@ -182,7 +244,6 @@
         userTracker.removeCallback(userTrackerCallback)
         contentResolver.unregisterContentObserver(settingsObserver)
         configurationController.removeCallback(configChangeListener)
-        statusBarStateController.removeCallback(statusBarStateListener)
         session = null
 
         plugin?.onTargetsAvailable(emptyList())
@@ -198,6 +259,13 @@
         plugin?.unregisterListener(listener)
     }
 
+    fun shiftSplitShadeSmartspace(y: Int, animate: Boolean) {
+        if (splitShadeContainer?.visibility == VISIBLE) {
+            PropertyAnimator.setProperty(splitShadeContainer, AnimatableProperty.Y, y.toFloat(),
+                    ANIMATION_PROPERTIES, animate)
+        }
+    }
+
     private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
         execution.assertIsMainThread()
         val filteredTargets = targets.filter(::filterSmartspaceTarget)
@@ -233,6 +301,23 @@
             execution.assertIsMainThread()
             smartspaceView.setDozeAmount(eased)
         }
+
+        override fun onDozingChanged(isDozing: Boolean) {
+            isAod = isDozing
+            updateSmartSpaceContainer()
+        }
+
+        override fun onStateChanged(newState: Int) {
+            if (newState == StatusBarState.KEYGUARD) {
+                if (isSmartspaceEnabled()) {
+                    updateSmartSpaceContainer()
+                }
+            } else {
+                splitShadeContainer?.visibility = GONE
+                singlePaneContainer?.visibility = GONE
+                disconnect()
+            }
+        }
     }
 
     private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
index 2537b19..129fa5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
@@ -20,6 +20,7 @@
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 /**
@@ -37,6 +38,9 @@
     /** Called when the user clicks "Manage" or "History" in the Shade. */
     void startHistoryIntent(View view, boolean showHistory);
 
+    /** Called when the user succeed to drop notification to proper target view. */
+    void onDragSuccess(NotificationEntry entry);
+
     default boolean isCollapsingToShowActivityOverLockscreen() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 0fb1c54..da70621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -43,6 +43,14 @@
     private final Optional<Bubbles> mBubblesOptional;
     private final NotificationActivityStarter mNotificationActivityStarter;
 
+    private ExpandableNotificationRow.OnDragSuccessListener mOnDragSuccessListener =
+            new ExpandableNotificationRow.OnDragSuccessListener() {
+                @Override
+                public void onDragSuccess(NotificationEntry entry) {
+                    mNotificationActivityStarter.onDragSuccess(entry);
+                }
+            };
+
     private NotificationClicker(
             NotificationClickerLogger logger,
             Optional<StatusBar> statusBarOptional,
@@ -111,8 +119,10 @@
         if (notification.contentIntent != null || notification.fullScreenIntent != null
                 || row.getEntry().isBubble()) {
             row.setOnClickListener(this);
+            row.setOnDragSuccessListener(mOnDragSuccessListener);
         } else {
             row.setOnClickListener(null);
+            row.setOnDragSuccessListener(null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 1ab2a9e..a65f3d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -37,7 +37,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8ae31cb..277b4ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -63,7 +63,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
 import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index d80cc08..25b2019 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -19,7 +19,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
index aec2647..518c3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.inflation;
 
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index db49e44..168e086 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -21,7 +21,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index f758114..55620b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -30,11 +30,11 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 32d90d3..c5899ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -20,7 +20,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.NotificationListener
 import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 4f3406c..acb0e82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -21,6 +21,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Point;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.util.MathUtils;
@@ -139,6 +140,8 @@
     private boolean mIsHeadsUpAnimation;
     private int mHeadsUpAddStartLocation;
     private float mHeadsUpLocation;
+    /* In order to track headsup longpress coorindate. */
+    protected Point mTargetPoint;
     private boolean mIsAppearing;
     private boolean mDismissed;
     private boolean mRefocusOnDismiss;
@@ -521,8 +524,8 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 mWasCancelled = false;
-                Configuration.Builder builder = new Configuration.Builder(getCujType(isAppearing))
-                        .setView(ActivatableNotificationView.this);
+                Configuration.Builder builder = Configuration.Builder
+                        .withView(getCujType(isAppearing), ActivatableNotificationView.this);
                 InteractionJankMonitor.getInstance().begin(builder);
             }
 
@@ -568,8 +571,19 @@
         final int actualHeight = getActualHeight();
         float bottom = actualHeight * interpolatedFraction;
 
-        setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
-                bottom + mAppearAnimationTranslation);
+        if (mTargetPoint != null) {
+            int width = getWidth();
+            float fraction = 1 - mAppearAnimationFraction;
+
+            setOutlineRect(mTargetPoint.x * fraction,
+                    mAnimationTranslationY
+                            + (mAnimationTranslationY - mTargetPoint.y) * fraction,
+                    width - (width - mTargetPoint.x) * fraction,
+                    actualHeight - (actualHeight - mTargetPoint.y) * fraction);
+        } else {
+            setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
+                    bottom + mAppearAnimationTranslation);
+        }
     }
 
     private float getInterpolatedAppearAnimationFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 73bb6cd..0d8e850 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -37,6 +37,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Path;
+import android.graphics.Point;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
@@ -260,6 +261,8 @@
     // Use #setLongPressPosition to optionally assign positional data with the long press.
     private LongPressListener mLongPressListener;
 
+    private ExpandableNotificationRowDragController mDragController;
+
     private boolean mGroupExpansionChanging;
 
     /**
@@ -331,6 +334,7 @@
                 }
             };
     private OnClickListener mOnClickListener;
+    private OnDragSuccessListener mOnDragSuccessListener;
     private boolean mHeadsupDisappearRunning;
     private View mChildAfterViewWhenDismissed;
     private View mGroupParentWhenDismissed;
@@ -1083,6 +1087,10 @@
         mLongPressListener = longPressListener;
     }
 
+    public void setDragController(ExpandableNotificationRowDragController dragController) {
+        mDragController = dragController;
+    }
+
     @Override
     public void setOnClickListener(@Nullable OnClickListener l) {
         super.setOnClickListener(l);
@@ -1329,6 +1337,7 @@
     public void dismiss(boolean refocusOnDismiss) {
         super.dismiss(refocusOnDismiss);
         setLongPressListener(null);
+        setDragController(null);
         mGroupParentWhenDismissed = mNotificationParent;
         mChildAfterViewWhenDismissed = null;
         mEntry.getIcons().getStatusBarIcon().setDismissed();
@@ -1637,6 +1646,8 @@
         }
         onHeightReset();
         requestLayout();
+
+        setTargetPoint(null);
     }
 
     public void showFeedbackIcon(boolean show, Pair<Integer, Integer> resIds) {
@@ -1727,6 +1738,29 @@
         mTranslateableViews.remove(mGutsStub);
     }
 
+    /**
+     * Called once when starting drag motion after opening notification guts,
+     * in case of notification that has {@link android.app.Notification#contentIntent}
+     * and it is to start an activity.
+     */
+    public void doDragCallback(float x, float y) {
+        if (mDragController != null) {
+            setTargetPoint(new Point((int) x, (int) y));
+            mDragController.startDragAndDrop(this);
+        }
+    }
+
+    public void setOnDragSuccessListener(OnDragSuccessListener listener) {
+        mOnDragSuccessListener = listener;
+    }
+
+    /**
+     * Called when a notification is dropped on proper target window.
+     */
+    public void dragAndDropSuccess() {
+        mOnDragSuccessListener.onDragSuccess(getEntry());
+    }
+
     private void doLongClickCallback() {
         doLongClickCallback(getWidth() / 2, getHeight() / 2);
     }
@@ -3255,6 +3289,16 @@
     }
 
     /**
+     * Called when notification drag and drop is finished successfully.
+     */
+    public interface OnDragSuccessListener {
+        /**
+         * @param entry NotificationEntry that succeed to drop on proper target window.
+         */
+        void onDragSuccess(NotificationEntry entry);
+    }
+
+    /**
      * Equivalent to View.OnClickListener with coordinates
      */
     public interface CoordinateOnClickListener {
@@ -3321,4 +3365,11 @@
             }
         }
     }
+
+    private void setTargetPoint(Point p) {
+        mTargetPoint = p;
+    }
+    public Point getTargetPoint() {
+        return mTargetPoint;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c9fcdac8..0662a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -25,6 +25,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -85,6 +86,8 @@
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     private final Optional<BubblesManager> mBubblesManagerOptional;
 
+    private final ExpandableNotificationRowDragController mDragController;
+
     @Inject
     public ExpandableNotificationRowController(
             ExpandableNotificationRow view,
@@ -109,7 +112,8 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
-            Optional<BubblesManager> bubblesManagerOptional) {
+            Optional<BubblesManager> bubblesManagerOptional,
+            ExpandableNotificationRowDragController dragController) {
         mView = view;
         mListContainer = listContainer;
         mActivatableNotificationViewController = activatableNotificationViewController;
@@ -134,6 +138,7 @@
         mFalsingCollector = falsingCollector;
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         mBubblesManagerOptional = bubblesManagerOptional;
+        mDragController = dragController;
     }
 
     /**
@@ -164,6 +169,10 @@
         );
         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         if (mAllowLongPress) {
+            if (mView.getResources().getBoolean(R.bool.config_notificationToContents)) {
+                mView.setDragController(mDragController);
+            }
+
             mView.setLongPressListener((v, x, y, item) -> {
                 if (mView.isSummaryWithChildren()) {
                     mView.expandNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
new file mode 100644
index 0000000..06b739b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.systemui.statusbar.notification.row;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import javax.inject.Inject;
+
+/**
+ * Controller for Notification to window.
+ */
+public class ExpandableNotificationRowDragController {
+    private static final String TAG = ExpandableNotificationRowDragController.class.getSimpleName();
+    private int mIconSize;
+
+    private final Context mContext;
+    private final HeadsUpManager mHeadsUpManager;
+
+    @Inject
+    public ExpandableNotificationRowDragController(Context context,
+            HeadsUpManager headsUpManager) {
+        mContext = context;
+        mHeadsUpManager = headsUpManager;
+
+        init();
+    }
+
+    private void init() {
+        mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.drag_and_drop_icon_size);
+    }
+
+    /**
+     * Called when drag event beyond the touchslop,
+     * and start drag and drop.
+     *
+     * @param view notification that was long pressed and started to drag and drop.
+     */
+    @VisibleForTesting
+    public void startDragAndDrop(View view) {
+        ExpandableNotificationRow enr = null;
+        if (view instanceof ExpandableNotificationRow) {
+            enr = (ExpandableNotificationRow) view;
+        }
+
+        StatusBarNotification sn = enr.getEntry().getSbn();
+        Notification notification = sn.getNotification();
+        final PendingIntent contentIntent = notification.contentIntent != null
+                ? notification.contentIntent
+                : notification.fullScreenIntent;
+        Bitmap iconBitmap = getBitmapFromDrawable(
+                getPkgIcon(enr.getEntry().getSbn().getPackageName()));
+
+        final ImageView snapshot = new ImageView(mContext);
+        snapshot.setImageBitmap(iconBitmap);
+        snapshot.layout(0, 0, mIconSize, mIconSize);
+
+        ClipDescription clipDescription = new ClipDescription("Drag And Drop",
+                new String[]{ClipDescription.MIMETYPE_APPLICATION_ACTIVITY});
+        Intent dragIntent = new Intent();
+        dragIntent.putExtra("android.intent.extra.PENDING_INTENT", contentIntent);
+        dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
+        ClipData.Item item = new ClipData.Item(dragIntent);
+        ClipData dragData = new ClipData(clipDescription, item);
+        View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
+        view.setOnDragListener(getDraggedViewDragListener());
+        view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL);
+    }
+
+
+    private Drawable getPkgIcon(String pkgName) {
+        Drawable pkgicon = null;
+        PackageManager pm = mContext.getPackageManager();
+        ApplicationInfo info;
+        try {
+            info = pm.getApplicationInfo(
+                    pkgName,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+            if (info != null) {
+                pkgicon = pm.getApplicationIcon(info);
+            } else {
+                Log.d(TAG, " application info is null ");
+                pkgicon = pm.getDefaultActivityIcon();
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.d(TAG, "can not find package with : " + pkgName);
+            pkgicon = pm.getDefaultActivityIcon();
+        }
+
+        return pkgicon;
+    }
+
+    private Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) {
+        final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bmp);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return bmp;
+    }
+
+    private View.OnDragListener getDraggedViewDragListener() {
+        return (view, dragEvent) -> {
+            switch (dragEvent.getAction()) {
+                case DragEvent.ACTION_DRAG_STARTED:
+                    view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                    if (view instanceof ExpandableNotificationRow) {
+                        ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
+                        if (enr.isPinned()) {
+                            mHeadsUpManager.releaseAllImmediately();
+                        } else {
+                            Dependency.get(ShadeController.class).animateCollapsePanels(
+                                    CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
+                        }
+                    }
+                    return true;
+                case DragEvent.ACTION_DRAG_ENDED:
+                    if (dragEvent.getResult()) {
+                        if (view instanceof ExpandableNotificationRow) {
+                            ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
+                            enr.dragAndDropSuccess();
+                        }
+                    }
+                    return true;
+            }
+            return false;
+        };
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 940cf66..880e558 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -81,7 +81,6 @@
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationShelfController;
 import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index f18513a..04129b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -68,13 +68,13 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -183,6 +183,8 @@
     private int mBarState;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
 
+    private View mLongPressedView;
+
     private final NotificationListContainerImpl mNotificationListContainer =
             new NotificationListContainerImpl();
 
@@ -492,6 +494,11 @@
                 }
 
                 @Override
+                public void onLongPressSent(View v) {
+                    mLongPressedView = v;
+                }
+
+                @Override
                 public void onBeginDrag(View v) {
                     mFalsingCollector.onNotificationStartDismissing();
                     mView.onSwipeBegin(v);
@@ -1435,6 +1442,10 @@
         return mDynamicPrivacyController.isInLockedDownShade();
     }
 
+    public boolean isLongPressInProgress() {
+        return mLongPressedView != null;
+    }
+
     /**
      * Set the dimmed state for all of the notification views.
      */
@@ -1472,6 +1483,11 @@
         mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
     }
 
+    /** */
+    public void setWillExpand(boolean willExpand) {
+        mView.setWillExpand(willExpand);
+    }
+
     /**
      * Set a listener to when scrolling changes.
      */
@@ -1684,17 +1700,23 @@
             mView.handleEmptySpaceClick(ev);
 
             NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+
+            boolean longPressWantsIt = false;
+            if (mLongPressedView != null) {
+                longPressWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+            }
             boolean expandWantsIt = false;
-            if (!mSwipeHelper.isSwiping()
+            if (mLongPressedView == null && !mSwipeHelper.isSwiping()
                     && !mView.getOnlyScrollingInThisMotion() && guts == null) {
                 expandWantsIt = mView.getExpandHelper().onInterceptTouchEvent(ev);
             }
             boolean scrollWantsIt = false;
-            if (!mSwipeHelper.isSwiping() && !mView.isExpandingNotification()) {
+            if (mLongPressedView == null && !mSwipeHelper.isSwiping()
+                    && !mView.isExpandingNotification()) {
                 scrollWantsIt = mView.onInterceptTouchEventScroll(ev);
             }
             boolean swipeWantsIt = false;
-            if (!mView.isBeingDragged()
+            if (mLongPressedView == null && !mView.isBeingDragged()
                     && !mView.isExpandingNotification()
                     && !mView.getExpandedInThisMotion()
                     && !mView.getOnlyScrollingInThisMotion()
@@ -1722,7 +1744,7 @@
                 InteractionJankMonitor.getInstance().begin(mView,
                         CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
             }
-            return swipeWantsIt || scrollWantsIt || expandWantsIt;
+            return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt;
         }
 
         @Override
@@ -1731,11 +1753,15 @@
             boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
                     || ev.getActionMasked() == MotionEvent.ACTION_UP;
             mView.handleEmptySpaceClick(ev);
+            boolean longPressWantsIt = false;
+            if (guts != null && mLongPressedView != null) {
+                longPressWantsIt = mSwipeHelper.onTouchEvent(ev);
+            }
             boolean expandWantsIt = false;
             boolean onlyScrollingInThisMotion = mView.getOnlyScrollingInThisMotion();
             boolean expandingNotification = mView.isExpandingNotification();
-            if (mView.getIsExpanded() && !mSwipeHelper.isSwiping() && !onlyScrollingInThisMotion
-                    && guts == null) {
+            if (mLongPressedView == null && mView.getIsExpanded()
+                    && !mSwipeHelper.isSwiping() && !onlyScrollingInThisMotion && guts == null) {
                 ExpandHelper expandHelper = mView.getExpandHelper();
                 if (isCancelOrUp) {
                     expandHelper.onlyObserveMovements(false);
@@ -1749,12 +1775,12 @@
                 }
             }
             boolean scrollerWantsIt = false;
-            if (mView.isExpanded() && !mSwipeHelper.isSwiping() && !expandingNotification
-                    && !mView.getDisallowScrollingInThisMotion()) {
+            if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
+                    && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
                 scrollerWantsIt = mView.onScrollTouch(ev);
             }
             boolean horizontalSwipeWantsIt = false;
-            if (!mView.isBeingDragged()
+            if (mLongPressedView == null && !mView.isBeingDragged()
                     && !expandingNotification
                     && !mView.getExpandedInThisMotion()
                     && !onlyScrollingInThisMotion
@@ -1780,7 +1806,7 @@
                 mView.setCheckForLeaveBehind(true);
             }
             traceJankOnTouchEvent(ev.getActionMasked(), scrollerWantsIt);
-            return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
+            return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || longPressWantsIt;
         }
 
         private void traceJankOnTouchEvent(int action, boolean scrollerWantsIt) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 1b4ae9e..2c810c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -157,15 +157,13 @@
         // After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf
         // to skip rendering them in the hardware layer. We do not set them invisible because that
         // runs invalidate & onDraw when these views return onscreen, which is more expensive.
+        if (shelf.getViewState().hidden) {
+            // When the shelf is hidden, it won't clip views, so we don't hide rows
+            return;
+        }
         final float shelfTop = shelf.getViewState().yTranslation;
 
         for (ExpandableView view : algorithmState.visibleChildren) {
-            if (view instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                if (row.isHeadsUp() || row.isHeadsUpAnimatingAway()) {
-                    continue;
-                }
-            }
             final float viewTop = view.getViewState().yTranslation;
             if (viewTop >= shelfTop) {
                 view.getViewState().alpha = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee12b4b..2702bf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -433,6 +433,7 @@
                     if (row.isDismissed()) {
                         needsAnimation = false;
                     }
+
                     NotificationEntry entry = row.getEntry();
                     StatusBarIconView icon = entry.getIcons().getStatusBarIcon();
                     final StatusBarIconView centeredIcon = entry.getIcons().getCenteredIcon();
@@ -442,7 +443,8 @@
                     if (icon.getParent() != null) {
                         icon.getLocationOnScreen(mTmpLocation);
                         float iconPosition = mTmpLocation[0] - icon.getTranslationX()
-                                + ViewState.getFinalTranslationX(icon) + icon.getWidth() * 0.25f;
+                                + ViewState.getFinalTranslationX(icon)
+                                + icon.getWidth() * 0.25f;
                         mHostLayout.getLocationOnScreen(mTmpLocation);
                         targetLocation = iconPosition - mTmpLocation[0];
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 6d6c0a3..1bd26c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -39,9 +39,9 @@
 
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index b4f8126..908cd34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -29,9 +29,9 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.R;
 import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6802472..7908d84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -33,7 +33,7 @@
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.tuner.TunerService;
 
@@ -231,7 +231,9 @@
      * possible if AOD isn't even enabled or if the flag is disabled.
      */
     public boolean canControlUnlockedScreenOff() {
-        return getAlwaysOn() && mFeatureFlags.useNewLockscreenAnimations();
+        return getAlwaysOn()
+                && mFeatureFlags.useNewLockscreenAnimations()
+                && !getDisplayNeedsBlanking();
     }
 
     private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index f4830fb..878fbbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -18,9 +18,7 @@
 
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.view.DisplayCutout;
 import android.view.View;
-import android.view.WindowInsets;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
@@ -61,7 +59,6 @@
     private final NotificationPanelViewController mNotificationPanelViewController;
     private final Consumer<ExpandableNotificationRow>
             mSetTrackingHeadsUp = this::setTrackingHeadsUp;
-    private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
     private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
     private final KeyguardBypassController mBypassController;
     private final StatusBarStateController mStatusBarStateController;
@@ -75,9 +72,6 @@
     float mAppearFraction;
     private ExpandableNotificationRow mTrackedChild;
     private boolean mShown;
-    private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
-            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-                    -> updatePanelTranslation();
     private final ViewClippingUtil.ClippingParameters mParentClippingParams =
             new ViewClippingUtil.ClippingParameters() {
                 @Override
@@ -134,10 +128,8 @@
         mStackScrollerController = stackScrollerController;
         mNotificationPanelViewController = notificationPanelViewController;
         notificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
-        notificationPanelViewController.setVerticalTranslationListener(mUpdatePanelTranslation);
         notificationPanelViewController.setHeadsUpAppearanceController(this);
         mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
-        mStackScrollerController.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mStackScrollerController.setHeadsUpAppearanceController(this);
         mClockView = clockView;
         mOperatorNameView = operatorNameView;
@@ -174,7 +166,6 @@
         mNotificationPanelViewController.setVerticalTranslationListener(null);
         mNotificationPanelViewController.setHeadsUpAppearanceController(null);
         mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
-        mStackScrollerController.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mDarkIconDispatcher.removeDarkReceiver(this);
     }
 
@@ -189,63 +180,6 @@
         updateHeader(entry);
     }
 
-    /** To count the distance from the window right boundary to scroller right boundary. The
-     * distance formula is the following:
-     *     Y = screenSize - (SystemWindow's width + Scroller.getRight())
-     * There are four modes MUST to be considered in Cut Out of RTL.
-     * No Cut Out:
-     *   Scroller + NB
-     *   NB + Scroller
-     *     => SystemWindow = NavigationBar's width
-     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
-     * Corner Cut Out or Tall Cut Out:
-     *   cut out + Scroller + NB
-     *   NB + Scroller + cut out
-     *     => SystemWindow = NavigationBar's width
-     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
-     * Double Cut Out:
-     *   cut out left + Scroller + (NB + cut out right)
-     *     SystemWindow = NavigationBar's width + cut out right width
-     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
-     *   (cut out left + NB) + Scroller + cut out right
-     *     SystemWindow = NavigationBar's width + cut out left width
-     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
-     * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
-     */
-    private int getRtlTranslation() {
-        if (mPoint == null) {
-            mPoint = new Point();
-        }
-
-        int realDisplaySize = 0;
-        if (mStackScrollerController.getDisplay() != null) {
-            mStackScrollerController.getDisplay().getRealSize(mPoint);
-            realDisplaySize = mPoint.x;
-        }
-
-        WindowInsets windowInset = mStackScrollerController.getRootWindowInsets();
-        DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
-        int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
-        int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
-        int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0;
-        int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0;
-        int leftInset = Math.max(sysWinLeft, cutoutLeft);
-        int rightInset = Math.max(sysWinRight, cutoutRight);
-
-        return leftInset + mStackScrollerController.getRight() + rightInset - realDisplaySize;
-    }
-
-    public void updatePanelTranslation() {
-        float newTranslation;
-        if (mStackScrollerController.isLayoutRtl()) {
-            newTranslation = getRtlTranslation();
-        } else {
-            newTranslation = mStackScrollerController.getLeft();
-        }
-        newTranslation += mStackScrollerController.getTranslationX();
-        mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
-    }
-
     private void updateTopEntry() {
         NotificationEntry newEntry = null;
         if (shouldBeVisible()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 91d503b..0a4e59c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
@@ -40,6 +41,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
@@ -81,6 +83,11 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.controls.ControlsServiceInfo;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.management.ControlsListingController;
+import com.android.systemui.controls.ui.ControlsActivity;
+import com.android.systemui.controls.ui.ControlsUiController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.IntentButtonProvider;
@@ -98,6 +105,8 @@
 import com.android.systemui.wallet.controller.QuickAccessWalletController;
 import com.android.systemui.wallet.ui.WalletActivity;
 
+import java.util.List;
+
 /**
  * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
  * text.
@@ -133,9 +142,12 @@
     private KeyguardAffordanceView mLeftAffordanceView;
 
     private ImageView mWalletButton;
+    private ImageView mControlsButton;
     private boolean mHasCard = false;
     private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
     private QuickAccessWalletController mQuickAccessWalletController;
+    private ControlsComponent mControlsComponent;
+    private boolean mControlServicesAvailable = false;
 
     private ViewGroup mIndicationArea;
     private TextView mIndicationText;
@@ -188,6 +200,19 @@
     private ActivityIntentHelper mActivityIntentHelper;
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
+    private ControlsListingController.ControlsListingCallback mListingCallback =
+            new ControlsListingController.ControlsListingCallback() {
+                public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
+                    boolean available = !serviceInfos.isEmpty();
+
+                    if (available != mControlServicesAvailable) {
+                        mControlServicesAvailable = available;
+                        updateControlsVisibility();
+                        updateAffordanceColors();
+                    }
+                }
+            };
+
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
     }
@@ -253,6 +278,7 @@
         mRightAffordanceView = findViewById(R.id.camera_button);
         mLeftAffordanceView = findViewById(R.id.left_button);
         mWalletButton = findViewById(R.id.wallet_button);
+        mControlsButton = findViewById(R.id.controls_button);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
@@ -276,6 +302,7 @@
         mIndicationPadding = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_area_padding);
         updateWalletVisibility();
+        updateControlsVisibility();
     }
 
     /**
@@ -328,6 +355,11 @@
             mQuickAccessWalletController.unregisterWalletChangeObservers(
                     WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
         }
+
+        if (mControlsComponent != null) {
+            mControlsComponent.getControlsListingController().ifPresent(
+                    c -> c.removeCallback(mListingCallback));
+        }
     }
 
     private void initAccessibility() {
@@ -369,13 +401,20 @@
         updateLeftAffordanceIcon();
 
         lp = mWalletButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width);
+        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
         mWalletButton.setLayoutParams(lp);
 
+        lp = mControlsButton.getLayoutParams();
+        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
+        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
+        mControlsButton.setLayoutParams(lp);
+
         mIndicationPadding = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_area_padding);
+
         updateWalletVisibility();
+        updateAffordanceColors();
     }
 
     private void updateRightAffordanceIcon() {
@@ -454,22 +493,38 @@
                 || !mQuickAccessWalletController.isWalletEnabled()
                 || !mHasCard) {
             mWalletButton.setVisibility(GONE);
-            mIndicationArea.setPadding(0, 0, 0, 0);
-        } else {
-            Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
-            if (tileIcon != null) {
-                mWalletButton.setImageDrawable(tileIcon);
+
+            if (mControlsButton.getVisibility() == GONE) {
+                mIndicationArea.setPadding(0, 0, 0, 0);
             }
-            mWalletButton.getDrawable().setTint(
-                    Utils.getColorAttr(
-                            mContext,
-                            com.android.internal.R.attr.textColorPrimary).getDefaultColor());
+        } else {
             mWalletButton.setVisibility(VISIBLE);
             mWalletButton.setOnClickListener(this::onWalletClick);
             mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
         }
     }
 
+    private void updateControlsVisibility() {
+        if (mControlsComponent == null) return;
+
+        boolean hasFavorites = mControlsComponent.getControlsController()
+                .map(c -> c.getFavorites().size() > 0)
+                .orElse(false);
+        if (mDozing
+                || !hasFavorites
+                || !mControlServicesAvailable
+                || mControlsComponent.getVisibility() != AVAILABLE) {
+            mControlsButton.setVisibility(GONE);
+            if (mWalletButton.getVisibility() == GONE) {
+                mIndicationArea.setPadding(0, 0, 0, 0);
+            }
+        } else {
+            mControlsButton.setVisibility(VISIBLE);
+            mControlsButton.setOnClickListener(this::onControlsClick);
+            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
+        }
+    }
+
     public boolean isLeftVoiceAssist() {
         return mLeftIsVoiceAssist;
     }
@@ -751,6 +806,9 @@
         if (mWalletButton.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mWalletButton, delay);
         }
+        if (mControlsButton.getVisibility() == View.VISIBLE) {
+            startFinishDozeAnimationElement(mControlsButton, delay);
+        }
         if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
             startFinishDozeAnimationElement(mLeftAffordanceView, delay);
             delay += DOZE_ANIMATION_STAGGER_DELAY;
@@ -824,6 +882,7 @@
         updateCameraVisibility();
         updateLeftAffordanceIcon();
         updateWalletVisibility();
+        updateControlsVisibility();
 
         if (dozing) {
             mOverlayContainer.setVisibility(INVISIBLE);
@@ -857,6 +916,7 @@
         mRightAffordanceView.setAlpha(alpha);
         mIndicationArea.setAlpha(alpha);
         mWalletButton.setAlpha(alpha);
+        mControlsButton.setAlpha(alpha);
     }
 
     private class DefaultLeftButton implements IntentButton {
@@ -950,6 +1010,32 @@
         mQuickAccessWalletController.queryWalletCards(mCardRetriever);
 
         updateWalletVisibility();
+        updateAffordanceColors();
+    }
+
+    private void updateAffordanceColors() {
+        int iconColor = Utils.getColorAttrDefaultColor(
+                mContext,
+                com.android.internal.R.attr.textColorPrimary);
+        mWalletButton.getDrawable().setTint(iconColor);
+        mControlsButton.getDrawable().setTint(iconColor);
+
+        ColorStateList bgColor = Utils.getColorAttr(
+                mContext,
+                com.android.internal.R.attr.colorSurface);
+        mWalletButton.setBackgroundTintList(bgColor);
+        mControlsButton.setBackgroundTintList(bgColor);
+    }
+
+    /**
+      * Initialize controls via the ControlsComponent
+      */
+    public void initControls(ControlsComponent controlsComponent) {
+        mControlsComponent = controlsComponent;
+        mControlsComponent.getControlsListingController().ifPresent(
+                c -> c.addCallback(mListingCallback));
+
+        updateAffordanceColors();
     }
 
     private void onWalletClick(View v) {
@@ -974,19 +1060,41 @@
         }
     }
 
+    private void onControlsClick(View v) {
+        if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+            return;
+        }
+
+        Intent intent = new Intent(mContext, ControlsActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
+                .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
+
+        if (mControlsComponent.getVisibility() == AVAILABLE) {
+            mContext.startActivity(intent);
+        } else {
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */);
+        }
+    }
+
     private class WalletCardRetriever implements
             QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
 
         @Override
         public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
             mHasCard = !response.getWalletCards().isEmpty();
+            Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
+            if (tileIcon != null) {
+                mWalletButton.setImageDrawable(tileIcon);
+            }
             updateWalletVisibility();
+            updateAffordanceColors();
         }
 
         @Override
         public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
             mHasCard = false;
             updateWalletVisibility();
+            updateAffordanceColors();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 6caeba2..c0600b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -232,6 +232,7 @@
         pw.println("  launchingAffordance: $launchingAffordance")
         pw.println("  qSExpanded: $qSExpanded")
         pw.println("  hasFaceFeature: $hasFaceFeature")
+        pw.println("  userHasDeviceEntryIntent: $userHasDeviceEntryIntent")
     }
 
     /** Registers a listener for bypass state changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index f77c052..19c2585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -33,23 +33,11 @@
  */
 public class KeyguardClockPositionAlgorithm {
     /**
-     * How much the clock height influences the shade position.
-     * 0 means nothing, 1 means move the shade up by the height of the clock
-     * 0.5f means move the shade up by half of the size of the clock.
-     */
-    private static float CLOCK_HEIGHT_WEIGHT = 0.7f;
-
-    /**
      * Margin between the bottom of the status view and the notification shade.
      */
     private int mStatusViewBottomMargin;
 
     /**
-     * Height of the parent view - display size in px.
-     */
-    private int mHeight;
-
-    /**
      * Height of {@link KeyguardStatusView}.
      */
     private int mKeyguardStatusHeight;
@@ -68,21 +56,6 @@
     private int mUserSwitchPreferredY;
 
     /**
-     * Whether or not there is a custom clock face on keyguard.
-     */
-    private boolean mHasCustomClock;
-
-    /**
-     * Whether or not the NSSL contains any visible notifications.
-     */
-    private boolean mHasVisibleNotifs;
-
-    /**
-     * Height of notification stack: Sum of height of each notification.
-     */
-    private int mNotificationStackHeight;
-
-    /**
      * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
      * avatar.
      */
@@ -148,6 +121,7 @@
     private int mUnlockedStackScrollerPadding;
 
     private boolean mIsSplitShade;
+    private int mSplitShadeSmartspaceHeight;
 
     /**
      * Refreshes the dimension values.
@@ -170,28 +144,25 @@
      * Sets up algorithm values.
      */
     public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
-            int notificationStackHeight, float panelExpansion, int parentHeight,
-            int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
-            boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
+            float panelExpansion,
+            int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY, float dark,
             float overStrechAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
-            float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
+            float qsExpansion, int cutoutTopInset, int splitShadeSmartspaceHeight,
+            boolean isSplitShade) {
         mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
                 userSwitchHeight);
         mMaxShadeBottom = maxShadeBottom;
-        mNotificationStackHeight = notificationStackHeight;
         mPanelExpansion = panelExpansion;
-        mHeight = parentHeight;
         mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
         mUserSwitchHeight = userSwitchHeight;
         mUserSwitchPreferredY = userSwitchPreferredY;
-        mHasCustomClock = hasCustomClock;
-        mHasVisibleNotifs = hasVisibleNotifs;
         mDarkAmount = dark;
         mOverStretchAmount = overStrechAmount;
         mBypassEnabled = bypassEnabled;
         mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
         mQsExpansion = qsExpansion;
         mCutoutTopInset = cutoutTopInset;
+        mSplitShadeSmartspaceHeight = splitShadeSmartspaceHeight;
         mIsSplitShade = isSplitShade;
     }
 
@@ -213,7 +184,7 @@
         if (mBypassEnabled) {
             return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
         } else if (mIsSplitShade) {
-            return clockYPosition;
+            return clockYPosition + mSplitShadeSmartspaceHeight;
         } else {
             return clockYPosition + mKeyguardStatusHeight;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 222ed63..a73cad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -42,9 +42,9 @@
 import android.widget.TextView;
 
 import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 
 import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 5d8d36e..8770e86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -26,6 +26,7 @@
 
 import com.android.keyguard.CarrierTextController;
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -50,6 +51,7 @@
     private final UserInfoController mUserInfoController;
     private final StatusBarIconController mStatusBarIconController;
     private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+    private final BatteryMeterViewController mBatteryMeterViewController;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -115,7 +117,8 @@
             BatteryController batteryController,
             UserInfoController userInfoController,
             StatusBarIconController statusBarIconController,
-            StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) {
+            StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
+            BatteryMeterViewController batteryMeterViewController) {
         super(view);
         mCarrierTextController = carrierTextController;
         mConfigurationController = configurationController;
@@ -124,6 +127,7 @@
         mUserInfoController = userInfoController;
         mStatusBarIconController = statusBarIconController;
         mTintedIconManagerFactory = tintedIconManagerFactory;
+        mBatteryMeterViewController = batteryMeterViewController;
 
         Resources r = getResources();
         mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
@@ -136,6 +140,7 @@
     protected void onInit() {
         super.onInit();
         mCarrierTextController.init();
+        mBatteryMeterViewController.init();
     }
 
     @Override
@@ -154,10 +159,16 @@
 
     @Override
     protected void onViewDetached() {
+        destroy();
+    }
+
+    @Override
+    public void destroy() {
         // Don't receive future #onViewAttached calls so that we don't accidentally have two
         // controllers registered for the same view.
         // TODO(b/194181195): This shouldn't be necessary.
-        destroy();
+        super.destroy();
+        mBatteryMeterViewController.destroy();
 
         mConfigurationController.removeCallback(mConfigurationListener);
         mAnimationScheduler.removeCallback(mAnimationCallback);
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 481a8ed..50db240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,7 +18,6 @@
 
 import static android.view.View.GONE;
 
-import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
 import static androidx.constraintlayout.widget.ConstraintSet.END;
 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
 import static androidx.constraintlayout.widget.ConstraintSet.START;
@@ -111,11 +110,15 @@
 import com.android.systemui.communal.CommunalSource;
 import com.android.systemui.communal.CommunalSourceMonitor;
 import com.android.systemui.communal.dagger.CommunalViewComponent;
+import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.idle.IdleHostView;
+import com.android.systemui.idle.IdleHostViewController;
+import com.android.systemui.idle.dagger.IdleViewComponent;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
@@ -144,6 +147,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -236,6 +240,7 @@
     private final HeightListener mHeightListener = new HeightListener();
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
     private final SettingsChangeObserver mSettingsChangeObserver;
+    private final LockscreenSmartspaceController mLockscreenSmartspaceController;
 
     @VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
             new StatusBarStateListener();
@@ -331,11 +336,13 @@
     private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
     private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
     private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+    private final IdleViewComponent.Factory mIdleViewComponentFactory;
     private final QSDetailDisplayer mQSDetailDisplayer;
     private final FragmentService mFragmentService;
     private final ScrimController mScrimController;
     private final PrivacyDotViewController mPrivacyDotViewController;
     private final QuickAccessWalletController mQuickAccessWalletController;
+    private final ControlsComponent mControlsComponent;
     private final NotificationRemoteInputManager mRemoteInputManager;
 
     // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
@@ -363,8 +370,12 @@
     @Nullable
     private CommunalHostViewController mCommunalViewController;
     private KeyguardStatusViewController mKeyguardStatusViewController;
+    @Nullable
+    private IdleHostViewController mIdleHostViewController;
     private LockIconViewController mLockIconViewController;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
+    private FrameLayout mSplitShadeSmartspaceContainer;
+
     private boolean mAnimateNextPositionUpdate;
     private float mQuickQsOffsetHeight;
     private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -669,6 +680,9 @@
     private int mScreenCornerRadius;
     private boolean mQSAnimatingHiddenFromCollapsed;
 
+    private int mQsClipTop;
+    private int mQsClipBottom;
+    private boolean mQsVisible;
     private final ContentResolver mContentResolver;
 
     private final Executor mUiExecutor;
@@ -743,6 +757,7 @@
             KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
             KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
             CommunalViewComponent.Factory communalViewComponentFactory,
+            IdleViewComponent.Factory idleViewComponentFactory,
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             QSDetailDisplayer qsDetailDisplayer,
             NotificationGroupManagerLegacy groupManager,
@@ -765,8 +780,10 @@
             @Main Executor uiExecutor,
             SecureSettings secureSettings,
             SplitShadeHeaderController splitShadeHeaderController,
+            LockscreenSmartspaceController lockscreenSmartspaceController,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            NotificationRemoteInputManager remoteInputManager) {
+            NotificationRemoteInputManager remoteInputManager,
+            ControlsComponent controlsComponent) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
                 statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
@@ -776,6 +793,7 @@
         mKeyguardMediaController = keyguardMediaController;
         mPrivacyDotViewController = privacyDotViewController;
         mQuickAccessWalletController = quickAccessWalletController;
+        mControlsComponent = controlsComponent;
         mMetricsLogger = metricsLogger;
         mActivityManager = activityManager;
         mConfigurationController = configurationController;
@@ -788,6 +806,7 @@
         mCommunalViewComponentFactory = communalViewComponentFactory;
         mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
         mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
+        mIdleViewComponentFactory = idleViewComponentFactory;
         mDepthController = notificationShadeDepthController;
         mContentResolver = contentResolver;
         mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
@@ -795,6 +814,7 @@
         mQSDetailDisplayer = qsDetailDisplayer;
         mFragmentService = fragmentService;
         mSettingsChangeObserver = new SettingsChangeObserver(handler);
+        mLockscreenSmartspaceController = lockscreenSmartspaceController;
         mShouldUseSplitNotificationShade =
                 Utils.shouldUseSplitNotificationShade(mResources);
         mView.setWillNotDraw(!DEBUG);
@@ -891,6 +911,9 @@
         mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
         mBigClockContainer = mView.findViewById(R.id.big_clock_container);
         mCommunalView = mView.findViewById(R.id.communal_host);
+        mSplitShadeSmartspaceContainer = mView.findViewById(R.id.split_shade_smartspace_container);
+        mLockscreenSmartspaceController.setSplitShadeContainer(mSplitShadeSmartspaceContainer);
+        mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
 
         UserAvatarView userAvatarView = null;
         KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -910,7 +933,8 @@
                 userAvatarView,
                 mKeyguardStatusBar,
                 keyguardUserSwitcherView,
-                mCommunalView);
+                mCommunalView,
+                mView.findViewById(R.id.idle_host_view));
         mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
         NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
                 R.id.notification_stack_scroller);
@@ -1003,18 +1027,23 @@
             UserAvatarView userAvatarView,
             KeyguardStatusBarView keyguardStatusBarView,
             KeyguardUserSwitcherView keyguardUserSwitcherView,
-            CommunalHostView communalView) {
+            CommunalHostView communalView,
+            IdleHostView idleHostView) {
         // Re-associate the KeyguardStatusViewController
         KeyguardStatusViewComponent statusViewComponent =
                 mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
         mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
         mKeyguardStatusViewController.init();
 
+        IdleViewComponent idleViewComponent = mIdleViewComponentFactory.build(idleHostView);
+        mIdleHostViewController = idleViewComponent.getIdleHostViewController();
+        mIdleHostViewController.init();
+
         KeyguardStatusBarViewComponent statusBarViewComponent =
                 mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
         if (mKeyguardStatusBarViewController != null) {
             // TODO(b/194181195): This shouldn't be necessary.
-            mKeyguardStatusBarViewController.onViewDetached();
+            mKeyguardStatusBarViewController.destroy();
         }
         mKeyguardStatusBarViewController =
                 statusBarViewComponent.getKeyguardStatusBarViewController();
@@ -1025,6 +1054,7 @@
                     mCommunalViewComponentFactory.build(communalView);
             mCommunalViewController =
                     communalViewComponent.getCommunalHostViewController();
+            mCommunalViewController.init();
         }
 
         if (mKeyguardUserSwitcherController != null) {
@@ -1113,7 +1143,7 @@
         mNotificationContainerParent.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
 
         updateKeyguardStatusViewAlignment(false /* animate */);
-
+        mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
         mKeyguardMediaController.refreshMediaPosition();
     }
 
@@ -1187,7 +1217,8 @@
 
         mBigClockContainer.removeAllViews();
         updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
-                mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView);
+                mKeyguardStatusBar, keyguardUserSwitcherView, mCommunalView,
+                mView.findViewById(R.id.idle_host_view));
 
         // Update keyguard bottom area
         int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1237,6 +1268,7 @@
         mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
         mKeyguardBottomArea.setFalsingManager(mFalsingManager);
         mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
+        mKeyguardBottomArea.initControls(mControlsComponent);
     }
 
     private void updateMaxDisplayedNotifications(boolean recompute) {
@@ -1375,16 +1407,15 @@
                         ? 1.0f : mInterpolatedDarkAmount;
         mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
                 totalHeight - bottomPadding,
-                mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
                 expandedFraction,
-                totalHeight,
                 mKeyguardStatusViewController.getLockscreenHeight(),
                 userIconHeight,
-                userSwitcherPreferredY, hasCustomClock(),
-                hasVisibleNotifications, darkamount, mOverStretchAmount,
+                userSwitcherPreferredY,
+                darkamount, mOverStretchAmount,
                 bypassEnabled, getUnlockedStackScrollerPadding(),
                 computeQsExpansionFraction(),
                 mDisplayTopInset,
+                mSplitShadeSmartspaceContainer.getHeight(),
                 mShouldUseSplitNotificationShade);
         mClockPositionAlgorithm.run(mClockPositionResult);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
@@ -1392,10 +1423,6 @@
         mKeyguardStatusViewController.updatePosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY,
                 mClockPositionResult.clockScale, animateClock);
-        // CommunalView's height is constrained to KeyguardStatusView. Match Y offset as well.
-        if (mCommunalViewController != null) {
-            mCommunalViewController.updatePositionY(mClockPositionResult.clockY, animateClock);
-        }
         if (mKeyguardQsUserSwitchController != null) {
             mKeyguardQsUserSwitchController.updatePosition(
                     mClockPositionResult.clockX,
@@ -1408,6 +1435,9 @@
                     mClockPositionResult.userSwitchY,
                     animateClock);
         }
+        // no need to translate in X axis - horizontal position is determined by constraints
+        mLockscreenSmartspaceController
+                .shiftSplitShadeSmartspace(mClockPositionResult.clockY, animateClock);
         updateNotificationTranslucency();
         updateClock();
     }
@@ -1431,20 +1461,6 @@
                 TransitionManager.beginDelayedTransition(mNotificationContainerParent, transition);
             }
 
-            // By default, the CommunalView is not shown. We set parameters as if it is shown, which
-            // are based on it being aligned with the start of the qs edge guide, like the
-            // notification stack scroller. These constraints cannot be expressed in the layout as
-            // they reference a peer rather than the parent.
-            constraintSet.connect(
-                    R.id.communal_host, START,
-                    R.id.qs_edge_guideline, START);
-            constraintSet.connect(
-                    R.id.communal_host, TOP,
-                    R.id.keyguard_status_view, TOP);
-            constraintSet.connect(
-                    R.id.communal_host, BOTTOM,
-                    R.id.keyguard_status_view, BOTTOM);
-
             constraintSet.applyTo(mNotificationContainerParent);
         }
     }
@@ -1597,6 +1613,7 @@
         if (mKeyguardUserSwitcherController != null) {
             mKeyguardUserSwitcherController.setAlpha(alpha);
         }
+        mLockscreenSmartspaceController.setSplitShadeSmartspaceAlpha(alpha);
     }
 
     public void animateToFullShade(long delay) {
@@ -2460,6 +2477,9 @@
             final int startTop = mKeyguardStatusAreaClipBounds.top;
             final int startRight = mKeyguardStatusAreaClipBounds.right;
             final int startBottom = mKeyguardStatusAreaClipBounds.bottom;
+            if (mQsClippingAnimation != null) {
+                mQsClippingAnimation.cancel();
+            }
             mQsClippingAnimation = ValueAnimator.ofFloat(0.0f, 1.0f);
             mQsClippingAnimation.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
             mQsClippingAnimation.setDuration(mNotificationBoundsAnimationDuration);
@@ -2523,9 +2543,12 @@
             mQsTranslationForFullShadeTransition = qsTranslation;
             updateQsFrameTranslation();
             float currentTranslation = mQsFrame.getTranslationY();
-            mQs.setFancyClipping((
-                    int) (top - currentTranslation),
-                    (int) (bottom - currentTranslation),
+            mQsClipTop = (int) (top - currentTranslation);
+            mQsClipBottom = (int) (bottom - currentTranslation);
+            mQsVisible = qsVisible;
+            mQs.setFancyClipping(
+                    mQsClipTop,
+                    mQsClipBottom,
                     radius, qsVisible
                     && !mShouldUseSplitNotificationShade);
         }
@@ -3363,7 +3386,10 @@
         switch (mBarState) {
             case KEYGUARD:
                 if (!mDozingOnDown) {
-                    if (mKeyguardBypassController.getBypassEnabled()) {
+                    if (mUpdateMonitor.isFaceEnrolled()
+                            && !mUpdateMonitor.isFaceDetectionRunning()
+                            && !mUpdateMonitor.getUserCanSkipBouncer(
+                                    KeyguardUpdateMonitor.getCurrentUser())) {
                         mUpdateMonitor.requestFaceAuth(true);
                     } else {
                         mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
@@ -3769,6 +3795,7 @@
     public void dozeTimeTick() {
         mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusViewController.dozeTimeTick();
+        mLockscreenSmartspaceController.requestSmartspaceUpdate();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
         }
@@ -3854,7 +3881,10 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dump(fd, pw, args);
-        pw.println("    gestureExclusionRect: " + calculateGestureExclusionRect());
+        pw.println("    gestureExclusionRect: " + calculateGestureExclusionRect()
+                + " applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom
+                + ") qsVisible(" + mQsVisible
+        );
         if (mKeyguardStatusBarViewController != null) {
             mKeyguardStatusBarViewController.dump(fd, pw, args);
         }
@@ -3988,7 +4018,9 @@
                 if (mStatusBar.isBouncerShowing()) {
                     return true;
                 }
-                if (mBar.panelEnabled() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
+                if (mBar.panelEnabled()
+                        && !mNotificationStackScrollLayoutController.isLongPressInProgress()
+                        && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
                     mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
                     mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
                     return true;
@@ -4040,6 +4072,7 @@
                     return true;
                 }
                 if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
+                        && !mNotificationStackScrollLayoutController.isLongPressInProgress()
                         && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
                     mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 1a404dc..d2a4a00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -296,8 +296,7 @@
 
         if (mKeyguardPreferredRefreshRate > 0) {
             boolean onKeyguard = state.mStatusBarState == StatusBarState.KEYGUARD
-                    && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway
-                    && !state.mDozing;
+                    && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
             if (onKeyguard
                     && mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
                 mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardPreferredRefreshRate;
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 323a112..27f08a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -1397,8 +1397,7 @@
 
     private void beginJankMonitoring(int cuj) {
         InteractionJankMonitor.Configuration.Builder builder =
-                new InteractionJankMonitor.Configuration.Builder(cuj)
-                        .setView(mView)
+                InteractionJankMonitor.Configuration.Builder.withView(cuj, mView)
                         .setTag(isFullyCollapsed() ? "Expand" : "Collapse");
         InteractionJankMonitor.getInstance().begin(builder);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c300b11..70a46b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -27,6 +27,7 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.Pair;
 import android.view.DisplayCutout;
 import android.view.Gravity;
@@ -42,7 +43,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.List;
@@ -52,7 +52,6 @@
     private static final String TAG = "PhoneStatusBarView";
     private static final boolean DEBUG = StatusBar.DEBUG;
     private static final boolean DEBUG_GESTURES = false;
-    private final CommandQueue mCommandQueue;
     private final StatusBarContentInsetsProvider mContentInsetsProvider;
 
     StatusBar mBar;
@@ -81,6 +80,8 @@
     @Nullable
     private List<StatusBar.ExpansionChangedListener> mExpansionChangedListeners;
 
+    private PanelEnabledProvider mPanelEnabledProvider;
+
     /**
      * Draw this many pixels into the left/right side of the cutout to optimally use the space
      */
@@ -89,7 +90,6 @@
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mCommandQueue = Dependency.get(CommandQueue.class);
         mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
     }
 
@@ -177,7 +177,11 @@
 
     @Override
     public boolean panelEnabled() {
-        return mCommandQueue.panelsEnabled();
+        if (mPanelEnabledProvider == null) {
+            Log.e(TAG, "panelEnabledProvider is null; defaulting to super class.");
+            return super.panelEnabled();
+        }
+        return mPanelEnabledProvider.panelEnabled();
     }
 
     @Override
@@ -294,6 +298,11 @@
         }
     }
 
+    /** Set the {@link PanelEnabledProvider} to use. */
+    public void setPanelEnabledProvider(PanelEnabledProvider panelEnabledProvider) {
+        mPanelEnabledProvider = panelEnabledProvider;
+    }
+
     private void updateScrimFraction() {
         float scrimFraction = mPanelFraction;
         if (mMinFraction < 1.0f) {
@@ -391,4 +400,10 @@
     protected boolean shouldPanelBeVisible() {
         return mHeadsUpVisible || super.shouldPanelBeVisible();
     }
+
+    /** An interface that will provide whether panel is enabled. */
+    interface PanelEnabledProvider {
+        /** Returns true if the panel is enabled and false otherwise. */
+        boolean panelEnabled();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java
new file mode 100644
index 0000000..b36b67d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.ViewController;
+
+/** Controller for {@link PhoneStatusBarView}. */
+public class PhoneStatusBarViewController extends ViewController<PhoneStatusBarView> {
+
+    protected PhoneStatusBarViewController(
+            PhoneStatusBarView view,
+            CommandQueue commandQueue) {
+        super(view);
+        mView.setPanelEnabledProvider(commandQueue::panelsEnabled);
+    }
+
+    @Override
+    protected void onViewAttached() {
+    }
+
+    @Override
+    protected void onViewDetached() {
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 44ed279..43a8630 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -136,12 +136,6 @@
     public static final float BUSY_SCRIM_ALPHA = 1f;
 
     /**
-     * The default scrim under the expanded bubble stack.
-     * This should not be lower than 0.54, otherwise we won't pass GAR.
-     */
-    public static final float BUBBLE_SCRIM_ALPHA = 0.6f;
-
-    /**
      * Scrim opacity that can have text on top.
      */
     public static final float GAR_SCRIM_ALPHA = 0.6f;
@@ -156,8 +150,6 @@
     private ScrimView mScrimInFront;
     private ScrimView mNotificationsScrim;
     private ScrimView mScrimBehind;
-    @Nullable
-    private ScrimView mScrimForBubble;
 
     private Runnable mScrimBehindChangeRunnable;
 
@@ -195,12 +187,10 @@
     private float mInFrontAlpha = NOT_INITIALIZED;
     private float mBehindAlpha = NOT_INITIALIZED;
     private float mNotificationsAlpha = NOT_INITIALIZED;
-    private float mBubbleAlpha = NOT_INITIALIZED;
 
     private int mInFrontTint;
     private int mBehindTint;
     private int mNotificationsTint;
-    private int mBubbleTint;
 
     private boolean mWallpaperVisibilityTimedOut;
     private int mScrimsVisibility;
@@ -229,7 +219,6 @@
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
         mScrimStateListener = lightBarController::setScrimState;
         mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
-        ScrimState.BUBBLE_EXPANDED.setBubbleAlpha(BUBBLE_SCRIM_ALPHA);
 
         mKeyguardStateController = keyguardStateController;
         mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -276,11 +265,10 @@
      * Attach the controller to the supplied views.
      */
     public void attachViews(ScrimView behindScrim, ScrimView notificationsScrim,
-                            ScrimView scrimInFront, @Nullable ScrimView scrimForBubble) {
+                            ScrimView scrimInFront) {
         mNotificationsScrim = notificationsScrim;
         mScrimBehind = behindScrim;
         mScrimInFront = scrimInFront;
-        mScrimForBubble = scrimForBubble;
         updateThemeColors();
 
         behindScrim.enableBottomEdgeConcave(mClipsQsScrim);
@@ -293,8 +281,7 @@
 
         final ScrimState[] states = ScrimState.values();
         for (int i = 0; i < states.length; i++) {
-            states[i].init(mScrimInFront, mScrimBehind, mScrimForBubble, mDozeParameters,
-                    mDockManager);
+            states[i].init(mScrimInFront, mScrimBehind, mDozeParameters, mDockManager);
             states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
             states[i].setDefaultScrimAlpha(mDefaultScrimAlpha);
         }
@@ -302,9 +289,6 @@
         mScrimBehind.setDefaultFocusHighlightEnabled(false);
         mNotificationsScrim.setDefaultFocusHighlightEnabled(false);
         mScrimInFront.setDefaultFocusHighlightEnabled(false);
-        if (mScrimForBubble != null) {
-            mScrimForBubble.setDefaultFocusHighlightEnabled(false);
-        }
         updateScrims();
         mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
     }
@@ -496,8 +480,7 @@
             boolean relevantState = (mState == ScrimState.UNLOCKED
                     || mState == ScrimState.KEYGUARD
                     || mState == ScrimState.SHADE_LOCKED
-                    || mState == ScrimState.PULSING
-                    || mState == ScrimState.BUBBLE_EXPANDED);
+                    || mState == ScrimState.PULSING);
             if (!(relevantState && mExpansionAffectsAlpha)) {
                 return;
             }
@@ -564,8 +547,7 @@
             mQsBottomVisible = qsBottomVisible;
             boolean relevantState = (mState == ScrimState.SHADE_LOCKED
                     || mState == ScrimState.KEYGUARD
-                    || mState == ScrimState.PULSING
-                    || mState == ScrimState.BUBBLE_EXPANDED);
+                    || mState == ScrimState.PULSING);
             if (!(relevantState && mExpansionAffectsAlpha)) {
                 return;
             }
@@ -627,11 +609,9 @@
         mInFrontTint = mState.getFrontTint();
         mBehindTint = mState.getBehindTint();
         mNotificationsTint = mState.getNotifTint();
-        mBubbleTint = mState.getBubbleTint();
 
         mInFrontAlpha = mState.getFrontAlpha();
         mBehindAlpha = mState.getBehindAlpha();
-        mBubbleAlpha = mState.getBubbleAlpha();
         mNotificationsAlpha = mState.getNotifAlpha();
 
         assertAlphasValid();
@@ -640,7 +620,7 @@
             return;
         }
 
-        if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
+        if (mState == ScrimState.UNLOCKED) {
             // Darken scrim as you pull down the shade when unlocked, unless the shade is expanding
             // because we're doing the screen off animation.
             if (!mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
@@ -744,7 +724,6 @@
         setOrAdaptCurrentAnimation(mScrimBehind);
         setOrAdaptCurrentAnimation(mNotificationsScrim);
         setOrAdaptCurrentAnimation(mScrimInFront);
-        setOrAdaptCurrentAnimation(mScrimForBubble);
         dispatchBackScrimState(mScrimBehind.getViewAlpha());
 
         // Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
@@ -852,11 +831,6 @@
         setScrimAlpha(mScrimBehind, mBehindAlpha);
         setScrimAlpha(mNotificationsScrim, mNotificationsAlpha);
 
-        if (mScrimForBubble != null) {
-            boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen;
-            mScrimForBubble.setColors(mColors, animateScrimForBubble);
-            setScrimAlpha(mScrimForBubble, mBubbleAlpha);
-        }
         // The animation could have all already finished, let's call onFinished just in case
         onFinished(mState);
         dispatchScrimsVisible();
@@ -909,8 +883,6 @@
             return "behind_scrim";
         } else if (scrim == mNotificationsScrim) {
             return "notifications_scrim";
-        } else if (scrim == mScrimForBubble) {
-            return "bubble_scrim";
         }
         return "unknown_scrim";
     }
@@ -983,8 +955,6 @@
             return mBehindAlpha;
         } else if (scrim == mNotificationsScrim) {
             return mNotificationsAlpha;
-        } else if (scrim == mScrimForBubble) {
-            return mBubbleAlpha;
         } else {
             throw new IllegalArgumentException("Unknown scrim view");
         }
@@ -997,8 +967,6 @@
             return mBehindTint;
         } else if (scrim == mNotificationsScrim) {
             return mNotificationsTint;
-        } else if (scrim == mScrimForBubble) {
-            return mBubbleTint;
         } else {
             throw new IllegalArgumentException("Unknown scrim view");
         }
@@ -1030,8 +998,7 @@
         }
         if (isAnimating(mScrimBehind)
                 || isAnimating(mNotificationsScrim)
-                || isAnimating(mScrimInFront)
-                || isAnimating(mScrimForBubble)) {
+                || isAnimating(mScrimInFront)) {
             if (callback != null && callback != mCallback) {
                 // Since we only notify the callback that we're finished once everything has
                 // finished, we need to make sure that any changing callbacks are also invoked
@@ -1058,13 +1025,9 @@
             mInFrontTint = Color.TRANSPARENT;
             mBehindTint = mState.getBehindTint();
             mNotificationsTint = mState.getNotifTint();
-            mBubbleTint = Color.TRANSPARENT;
             updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
             updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
             updateScrimColor(mNotificationsScrim, mNotificationsAlpha, mNotificationsTint);
-            if (mScrimForBubble != null) {
-                updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
-            }
         }
     }
 
@@ -1232,14 +1195,6 @@
         pw.print(" tint=0x");
         pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
 
-        pw.print("  bubbleScrim:");
-        pw.print(" viewAlpha=");
-        pw.print(mScrimForBubble.getViewAlpha());
-        pw.print(" alpha=");
-        pw.print(mBubbleAlpha);
-        pw.print(" tint=0x");
-        pw.println(Integer.toHexString(mScrimForBubble.getTint()));
-
         pw.print("  mTracking=");
         pw.println(mTracking);
         pw.print("  mDefaultScrimAlpha=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0681193..e33c9f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,8 +19,6 @@
 import android.graphics.Color;
 import android.os.Trace;
 
-import androidx.annotation.Nullable;
-
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -43,11 +41,9 @@
         public void prepare(ScrimState previousState) {
             mFrontTint = Color.BLACK;
             mBehindTint = Color.BLACK;
-            mBubbleTint = previousState.mBubbleTint;
 
             mFrontAlpha = 1f;
             mBehindAlpha = 1f;
-            mBubbleAlpha = previousState.mBubbleAlpha;
 
             mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
         }
@@ -81,12 +77,10 @@
             mFrontTint = Color.BLACK;
             mBehindTint = Color.BLACK;
             mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
-            mBubbleTint = Color.TRANSPARENT;
 
             mFrontAlpha = 0;
             mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
             mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
-            mBubbleAlpha = 0;
             if (mClipQsScrim) {
                 updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
             }
@@ -118,7 +112,6 @@
             mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
             mNotifTint = Color.TRANSPARENT;
             mFrontAlpha = 0f;
-            mBubbleAlpha = 0f;
         }
     },
 
@@ -129,7 +122,6 @@
         @Override
         public void prepare(ScrimState previousState) {
             mBehindAlpha = 0;
-            mBubbleAlpha = 0f;
             mFrontAlpha = mDefaultScrimAlpha;
         }
     },
@@ -139,7 +131,6 @@
         public void prepare(ScrimState previousState) {
             mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
             mNotifAlpha = 1f;
-            mBubbleAlpha = 0f;
             mFrontAlpha = 0f;
             mBehindTint = Color.BLACK;
 
@@ -163,7 +154,6 @@
         public void prepare(ScrimState previousState) {
             mBehindAlpha = 0;
             mFrontAlpha = 0;
-            mBubbleAlpha = 0;
         }
     },
 
@@ -185,9 +175,6 @@
             mBehindTint = Color.BLACK;
             mBehindAlpha = ScrimController.TRANSPARENT;
 
-            mBubbleTint = Color.TRANSPARENT;
-            mBubbleAlpha = ScrimController.TRANSPARENT;
-
             mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
             // DisplayPowerManager may blank the screen for us, or we might blank it for ourselves
             // by animating the screen off via the LightRevelScrim. In either case we just need to
@@ -214,7 +201,6 @@
         @Override
         public void prepare(ScrimState previousState) {
             mFrontAlpha = mAodFrontScrimAlpha;
-            mBubbleAlpha = 0f;
             mBehindTint = Color.BLACK;
             mFrontTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
@@ -238,7 +224,6 @@
             mBehindAlpha = mClipQsScrim ? 1 : 0;
             mNotifAlpha = 0;
             mFrontAlpha = 0;
-            mBubbleAlpha = 0;
 
             mAnimationDuration = mKeyguardFadingAway
                     ? mKeyguardFadingAwayDuration
@@ -248,21 +233,16 @@
 
             mFrontTint = Color.TRANSPARENT;
             mBehindTint = Color.BLACK;
-            mBubbleTint = Color.TRANSPARENT;
             mBlankScreen = false;
 
             if (previousState == ScrimState.AOD) {
                 // Set all scrims black, before they fade transparent.
                 updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
                 updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
-                if (mScrimForBubble != null) {
-                    updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */);
-                }
 
                 // Scrims should still be black at the end of the transition.
                 mFrontTint = Color.BLACK;
                 mBehindTint = Color.BLACK;
-                mBubbleTint = Color.BLACK;
                 mBlankScreen = true;
             }
 
@@ -270,45 +250,24 @@
                 updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
             }
         }
-    },
-
-    /**
-     * Unlocked with a bubble expanded.
-     */
-    BUBBLE_EXPANDED {
-        @Override
-        public void prepare(ScrimState previousState) {
-            mFrontTint = Color.TRANSPARENT;
-            mBehindTint = Color.TRANSPARENT;
-            mBubbleTint = Color.BLACK;
-
-            mFrontAlpha = 0f;
-            mBehindAlpha = mDefaultScrimAlpha;
-
-            mAnimationDuration = ScrimController.ANIMATION_DURATION;
-            mBlankScreen = false;
-        }
     };
 
     boolean mBlankScreen = false;
     long mAnimationDuration = ScrimController.ANIMATION_DURATION;
     int mFrontTint = Color.TRANSPARENT;
     int mBehindTint = Color.TRANSPARENT;
-    int mBubbleTint = Color.TRANSPARENT;
     int mNotifTint = Color.TRANSPARENT;
 
     boolean mAnimateChange = true;
     float mAodFrontScrimAlpha;
     float mFrontAlpha;
     float mBehindAlpha;
-    float mBubbleAlpha;
     float mNotifAlpha;
 
     float mScrimBehindAlphaKeyguard;
     float mDefaultScrimAlpha;
     ScrimView mScrimInFront;
     ScrimView mScrimBehind;
-    @Nullable ScrimView mScrimForBubble;
 
     DozeParameters mDozeParameters;
     DockManager mDockManager;
@@ -321,11 +280,10 @@
     long mKeyguardFadingAwayDuration;
     boolean mClipQsScrim;
 
-    public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
-            DozeParameters dozeParameters, DockManager dockManager) {
+    public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
+            DockManager dockManager) {
         mScrimInFront = scrimInFront;
         mScrimBehind = scrimBehind;
-        mScrimForBubble = scrimForBubble;
 
         mDozeParameters = dozeParameters;
         mDockManager = dockManager;
@@ -352,10 +310,6 @@
         return mNotifAlpha;
     }
 
-    public float getBubbleAlpha() {
-        return mBubbleAlpha;
-    }
-
     public int getFrontTint() {
         return mFrontTint;
     }
@@ -368,10 +322,6 @@
         return mNotifTint;
     }
 
-    public int getBubbleTint() {
-        return mBubbleTint;
-    }
-
     public long getAnimationDuration() {
         return mAnimationDuration;
     }
@@ -409,10 +359,6 @@
         mDefaultScrimAlpha = defaultScrimAlpha;
     }
 
-    public void setBubbleAlpha(float alpha) {
-        mBubbleAlpha = alpha;
-    }
-
     public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
         mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index 70f3436..4b7fe4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -17,10 +17,11 @@
 package com.android.systemui.statusbar.phone
 
 import android.view.View
-import com.android.systemui.BatteryMeterView
 import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
 import javax.inject.Inject
@@ -31,7 +32,8 @@
     @Named(SPLIT_SHADE_HEADER) private val statusBar: View,
     private val statusBarIconController: StatusBarIconController,
     qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
-    featureFlags: FeatureFlags
+    featureFlags: FeatureFlags,
+    batteryMeterViewController: BatteryMeterViewController
 ) {
 
     // TODO(b/194178072) Handle RSSI hiding when multi carrier
@@ -52,9 +54,11 @@
         }
 
     init {
+        batteryMeterViewController.init()
         val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+
         // battery settings same as in QS icons
-        batteryIcon.setIgnoreTunerUpdates(true)
+        batteryMeterViewController.ignoreTunerUpdates()
         batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
         val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 5011c09..82358a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -18,7 +18,6 @@
 
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.app.StatusBarManager.WindowType;
 import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -32,16 +31,12 @@
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
 import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import static com.android.wm.shell.bubbles.BubbleController.TASKBAR_CHANGED_BROADCAST;
 
@@ -71,13 +66,10 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -89,8 +81,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
@@ -105,8 +95,6 @@
 import android.view.Display;
 import android.view.IRemoteAnimationRunner;
 import android.view.IWindowManager;
-import android.view.InsetsState.InternalInsetsType;
-import android.view.InsetsVisibilities;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationAdapter;
@@ -114,7 +102,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowInsetsController.Appearance;
-import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
@@ -134,7 +121,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.RegisterStatusBarResult;
-import com.android.internal.view.AppearanceRegion;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
@@ -147,10 +133,10 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.DelegateLaunchAnimatorController;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.biometrics.AuthRippleController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.camera.CameraIntents;
@@ -158,13 +144,11 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.emergency.EmergencyGesture;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.keyguard.KeyguardService;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -187,12 +171,10 @@
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.settings.brightness.BrightnessSlider;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.statusbar.AutoHideUiElement;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CircleReveal;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -212,14 +194,11 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
@@ -242,13 +221,13 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.startingsurface.SplashscreenContentDrawer;
@@ -268,10 +247,10 @@
 
 import dagger.Lazy;
 
-public class StatusBar extends SystemUI implements DemoMode,
-        ActivityStarter, KeyguardStateController.Callback,
-        OnHeadsUpChangedListener, CommandQueue.Callbacks,
-        ColorExtractor.OnColorsChangedListener, ConfigurationListener,
+/** */
+public class StatusBar extends SystemUI implements
+        ActivityStarter,
+        ConfigurationListener,
         StatusBarStateController.StateListener,
         LifecycleOwner, BatteryController.BatteryStateChangeCallback,
         ActivityLaunchAnimator.Callback {
@@ -284,7 +263,6 @@
     protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
 
     // Should match the values in PhoneWindowManager
-    public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
 
@@ -316,7 +294,7 @@
     // 1020-1040 reserved for BaseStatusBar
 
     // Time after we abort the launch transition.
-    private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
+    static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
 
     protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
@@ -325,11 +303,6 @@
      */
     private static final int HINT_RESET_DELAY_MS = 1200;
 
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
     public static final int FADE_KEYGUARD_START_DELAY = 100;
     public static final int FADE_KEYGUARD_DURATION = 300;
     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
@@ -355,14 +328,113 @@
         try {
             IPackageManager packageManager =
                     IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
-            onlyCoreApps = packageManager.isOnlyCoreApps();
+            onlyCoreApps = packageManager != null && packageManager.isOnlyCoreApps();
         } catch (RemoteException e) {
             onlyCoreApps = false;
         }
         ONLY_CORE_APPS = onlyCoreApps;
     }
 
-    private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
+
+    void setWindowState(int state) {
+        mStatusBarWindowState =  state;
+        mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
+    }
+
+    void acquireGestureWakeLock(long time) {
+        mGestureWakeLock.acquire(time);
+    }
+
+    boolean setAppearance(int appearance) {
+        if (mAppearance != appearance) {
+            mAppearance = appearance;
+            return updateBarMode(barMode(isTransientShown(), appearance));
+        }
+
+        return false;
+    }
+
+    int getBarMode() {
+        return mStatusBarMode;
+    }
+
+    boolean getWereIconsJustHidden() {
+        return mWereIconsJustHidden;
+    }
+
+    void setWereIconsJustHidden(boolean justHidden) {
+        mWereIconsJustHidden = justHidden;
+    }
+
+    void resetHandlerMsg(int msg) {
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    Handler getHandler() {
+        return mHandler;
+    }
+
+    int getDisabled1() {
+        return mDisabled1;
+    }
+
+    void setDisabled1(int disabled) {
+        mDisabled1 = disabled;
+    }
+
+    int getDisabled2() {
+        return mDisabled2;
+    }
+
+    void setDisabled2(int disabled) {
+        mDisabled2 = disabled;
+    }
+
+    void setLastCameraLaunchSource(int source) {
+        mLastCameraLaunchSource = source;
+    }
+
+    void setLaunchCameraOnFinishedGoingToSleep(boolean launch) {
+        mLaunchCameraOnFinishedGoingToSleep = launch;
+    }
+
+    void setLaunchCameraOnFinishedWaking(boolean launch) {
+        mLaunchCameraWhenFinishedWaking = launch;
+    }
+
+    void setLaunchEmergencyActionOnFinishedGoingToSleep(boolean launch) {
+        mLaunchEmergencyActionOnFinishedGoingToSleep = launch;
+    }
+
+    void setLaunchEmergencyActionOnFinishedWaking(boolean launch) {
+        mLaunchEmergencyActionWhenFinishedWaking = launch;
+    }
+
+    void setTopHidesStatusBar(boolean hides) {
+        mTopHidesStatusBar = hides;
+    }
+
+    QSPanelController getQSPanelController() {
+        return mQSPanelController;
+    }
+
+    /** */
+    public void animateExpandNotificationsPanel() {
+        mCommandQueueCallbacks.animateExpandNotificationsPanel();
+    }
+
+    /** */
+    public void animateExpandSettingsPanel(@Nullable String subpanel) {
+        mCommandQueueCallbacks.animateExpandSettingsPanel(subpanel);
+    }
+
+    /** */
+    public void animateCollapsePanels(int flags, boolean force) {
+        mCommandQueueCallbacks.animateCollapsePanels(flags, force);
+    }
 
     public interface ExpansionChangedListener {
         void onExpansionChanged(float expansion, boolean expanded);
@@ -374,8 +446,7 @@
     protected int mState; // TODO: remove this. Just use StatusBarStateController
     protected boolean mBouncerShowing;
 
-    private PhoneStatusBarPolicy mIconPolicy;
-    private StatusBarSignalPolicy mSignalPolicy;
+    private final PhoneStatusBarPolicy mIconPolicy;
 
     private final VolumeComponent mVolumeComponent;
     private BrightnessMirrorController mBrightnessMirrorController;
@@ -386,14 +457,13 @@
     @Nullable
     protected LockscreenWallpaper mLockscreenWallpaper;
     private final AutoHideController mAutoHideController;
-    @Nullable
-    private final KeyguardLiftController mKeyguardLiftController;
 
     private final Point mCurrentDisplaySize = new Point();
 
     protected NotificationShadeWindowView mNotificationShadeWindowView;
     protected StatusBarWindowView mPhoneStatusBarWindow;
     protected PhoneStatusBarView mStatusBarView;
+    private PhoneStatusBarViewController mPhoneStatusBarViewController;
     private AuthRippleController mAuthRippleController;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     protected NotificationShadeWindowController mNotificationShadeWindowController;
@@ -404,7 +474,6 @@
     private boolean mWakeUpComingFromTouch;
     private PointF mWakeUpTouchLocation;
     private LightRevealScrim mLightRevealScrim;
-    private WiredChargingRippleController mChargingRippleAnimationController;
     private PowerButtonReveal mPowerButtonReveal;
 
     private final Object mQueueLock = new Object();
@@ -438,9 +507,8 @@
     private final KeyguardDismissUtil mKeyguardDismissUtil;
     private final ExtensionController mExtensionController;
     private final UserInfoControllerImpl mUserInfoControllerImpl;
-    private final DismissCallbackRegistry mDismissCallbackRegistry;
     private final DemoModeController mDemoModeController;
-    private NotificationsController mNotificationsController;
+    private final NotificationsController mNotificationsController;
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
     private final StatusBarLocationPublisher mStatusBarLocationPublisher;
@@ -455,8 +523,6 @@
 
     KeyguardIndicationController mKeyguardIndicationController;
 
-    private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
-
     private View mReportRejectedTouch;
 
     private boolean mExpandedVisible;
@@ -473,15 +539,18 @@
     private final UnfoldTransitionConfig mUnfoldTransitionConfig;
     private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    private final WallpaperManager mWallpaperManager;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    private final TunerService mTunerService;
 
     private final List<ExpansionChangedListener> mExpansionChangedListeners;
 
-    // for disabling the status bar
+    // Flags for disabling the status bar
+    // Two variables becaseu the first one evidently ran out of room for new flags.
     private int mDisabled1 = 0;
     private int mDisabled2 = 0;
 
-    /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
+    /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
 
     private boolean mTransientShown;
@@ -567,7 +636,7 @@
     private int mInteractingWindows;
     private @TransitionMode int mStatusBarMode;
 
-    private ViewMediatorCallback mKeyguardViewMediatorCallback;
+    private final ViewMediatorCallback mKeyguardViewMediatorCallback;
     private final ScrimController mScrimController;
     protected DozeScrimController mDozeScrimController;
     private final Executor mUiBgExecutor;
@@ -587,8 +656,7 @@
                 Log.wtf(TAG, "WallpaperManager not supported");
                 return;
             }
-            WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
-            WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
+            WallpaperInfo info = mWallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
             // If WallpaperInfo is null, it must be ImageWallpaper.
@@ -603,22 +671,17 @@
     BroadcastReceiver mTaskbarChangeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (mBubblesOptional.isPresent()) {
-                mBubblesOptional.get().onTaskbarChanged(intent.getExtras());
-            }
+            mBubblesOptional.ifPresent(bubbles -> bubbles.onTaskbarChanged(intent.getExtras()));
         }
     };
 
     private Runnable mLaunchTransitionEndRunnable;
-    private NotificationEntry mDraggedDownEntry;
     private boolean mLaunchCameraWhenFinishedWaking;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
     private boolean mLaunchEmergencyActionWhenFinishedWaking;
     private boolean mLaunchEmergencyActionOnFinishedGoingToSleep;
     private int mLastCameraLaunchSource;
     protected PowerManager.WakeLock mGestureWakeLock;
-    private Vibrator mVibrator;
-    private VibrationEffect mCameraLaunchGestureVibrationEffect;
 
     private final int[] mTmpInt2 = new int[2];
 
@@ -702,20 +765,22 @@
     private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
-    private boolean mVibrateOnOpening;
-    private final VibratorHelper mVibratorHelper;
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
     protected StatusBarNotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
-    private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
+    private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
     private final Optional<BubblesManager> mBubblesManagerOptional;
     private final Optional<Bubbles> mBubblesOptional;
     private final Bubbles.BubbleExpandListener mBubbleExpandListener;
     private final Optional<StartingSurface> mStartingSurfaceOptional;
 
-    private ActivityIntentHelper mActivityIntentHelper;
+    private final ActivityIntentHelper mActivityIntentHelper;
     private NotificationStackScrollLayoutController mStackScrollerController;
+    private BatteryMeterViewController mBatteryMeterViewController;
+
+    private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
+            (extractor, which) -> updateTheme();
 
     /**
      * Public constructor for StatusBar.
@@ -730,7 +795,6 @@
             LightBarController lightBarController,
             AutoHideController autoHideController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            StatusBarSignalPolicy signalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -741,7 +805,6 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
-            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -760,19 +823,16 @@
             ScreenLifecycle screenLifecycle,
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
-            VibratorHelper vibratorHelper,
             Optional<BubblesManager> bubblesManagerOptional,
             Optional<Bubbles> bubblesOptional,
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
-            @Nullable KeyguardLiftController keyguardLiftController,
             Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
@@ -799,13 +859,11 @@
             UserInfoControllerImpl userInfoControllerImpl,
             PhoneStatusBarPolicy phoneStatusBarPolicy,
             KeyguardIndicationController keyguardIndicationController,
-            DismissCallbackRegistry dismissCallbackRegistry,
             DemoModeController demoModeController,
             Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             NotificationIconAreaController notificationIconAreaController,
             BrightnessSlider.Factory brightnessSliderFactory,
-            WiredChargingRippleController chargingRippleAnimationController,
             UnfoldTransitionConfig unfoldTransitionConfig,
             Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
             OngoingCallController ongoingCallController,
@@ -815,14 +873,15 @@
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             FeatureFlags featureFlags,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+            WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         super(context);
         mNotificationsController = notificationsController;
         mLightBarController = lightBarController;
         mAutoHideController = autoHideController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
-        mSignalPolicy = signalPolicy;
         mPulseExpansionHandler = pulseExpansionHandler;
         mWakeUpCoordinator = notificationWakeUpCoordinator;
         mKeyguardBypassController = keyguardBypassController;
@@ -835,7 +894,6 @@
         mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
-        mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
         mGutsManager = notificationGutsManager;
         mNotificationLogger = notificationLogger;
         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -854,7 +912,6 @@
         mScreenLifecycle = screenLifecycle;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mStatusBarStateController = statusBarStateController;
-        mVibratorHelper = vibratorHelper;
         mBubblesManagerOptional = bubblesManagerOptional;
         mBubblesOptional = bubblesOptional;
         mVisualStabilityManager = visualStabilityManager;
@@ -867,7 +924,6 @@
         mPowerManager = powerManager;
         mDozeParameters = dozeParameters;
         mScrimController = scrimController;
-        mKeyguardLiftController = keyguardLiftController;
         mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
         mScreenPinningRequest = screenPinningRequest;
         mDozeScrimController = dozeScrimController;
@@ -890,11 +946,9 @@
         mExtensionController = extensionController;
         mUserInfoControllerImpl = userInfoControllerImpl;
         mIconPolicy = phoneStatusBarPolicy;
-        mDismissCallbackRegistry = dismissCallbackRegistry;
         mDemoModeController = demoModeController;
         mNotificationIconAreaController = notificationIconAreaController;
         mBrightnessSliderFactory = brightnessSliderFactory;
-        mChargingRippleAnimationController = chargingRippleAnimationController;
         mUnfoldTransitionConfig = unfoldTransitionConfig;
         mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
         mOngoingCallController = ongoingCallController;
@@ -903,7 +957,9 @@
         mStatusBarIconController = statusBarIconController;
         mFeatureFlags = featureFlags;
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+        mWallpaperManager = wallpaperManager;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+        mTunerService = tunerService;
 
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mStartingSurfaceOptional = startingSurfaceOptional;
@@ -912,12 +968,10 @@
         mExpansionChangedListeners = new ArrayList<>();
 
         mBubbleExpandListener =
-                (isExpanding, key) -> {
-                    mContext.getMainExecutor().execute(() -> {
-                        mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
-                        updateScrimController();
-                    });
-                };
+                (isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
+                    mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
+                    updateScrimController();
+                });
 
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         DateTimeView.setReceiverHandler(timeTickHandler);
@@ -937,7 +991,7 @@
 
         mKeyguardIndicationController.init();
 
-        mColorExtractor.addOnColorsChangedListener(this);
+        mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
         mStatusBarStateController.addCallback(this,
                 SysuiStatusBarStateController.RANK_STATUS_BAR);
 
@@ -945,13 +999,10 @@
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
 
-        mDisplay = mWindowManager.getDefaultDisplay();
+        mDisplay = mContext.getDisplay();
         mDisplayId = mDisplay.getDisplayId();
         updateDisplaySize();
 
-        mVibrateOnOpening = mContext.getResources().getBoolean(
-                R.bool.config_vibrateOnIconAnimation);
-
         // start old BaseStatusBar.start().
         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
@@ -965,14 +1016,7 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mWallpaperSupported =
-                mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
-
-        // Connect in to the status bar manager service
-        mCommandQueue.addCallback(this);
-
-        // Listen for demo mode changes
-        mDemoModeController.addCallback(this);
+        mWallpaperSupported = mWallpaperManager.isWallpaperSupported();
 
         RegisterStatusBarResult result = null;
         try {
@@ -999,13 +1043,13 @@
         if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
             showTransientUnchecked();
         }
-        onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
-                result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedVisibilities,
-                result.mPackageName);
+        mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
+                result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior,
+                result.mRequestedVisibilities, result.mPackageName);
 
         // StatusBarManagerService has a back up of IME token and it's restored here.
-        setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
-                result.mImeBackDisposition, result.mShowImeSwitcher);
+        mCommandQueueCallbacks.setImeWindowStatus(mDisplayId, result.mImeToken,
+                result.mImeWindowVis, result.mImeBackDisposition, result.mShowImeSwitcher);
 
         // Set up the initial icon state
         int numIcons = result.mIcons.size();
@@ -1044,7 +1088,13 @@
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy.init();
 
-        mKeyguardStateController.addCallback(this);
+        mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+            @Override
+            public void onUnlockedChanged() {
+                updateKeyguardState();
+                logStateToEventlog();
+            }
+        });
         startKeyguard();
 
         mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
@@ -1075,7 +1125,7 @@
 
         mPluginManager.addPluginListener(
                 new PluginListener<OverlayPlugin>() {
-                    private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
+                    private final ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
 
                     @Override
                     public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
@@ -1124,7 +1174,6 @@
     // Constructing the view
     // ================================================================================
     protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
-        final Context context = mContext;
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
         updateTheme();
@@ -1162,6 +1211,19 @@
                     mStatusBarView.setPanel(mNotificationPanelViewController);
                     mStatusBarView.setScrimController(mScrimController);
                     mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+                    mPhoneStatusBarViewController =
+                            new PhoneStatusBarViewController(mStatusBarView, mCommandQueue);
+                    mPhoneStatusBarViewController.init();
+
+                    mBatteryMeterViewController = new BatteryMeterViewController(
+                            mStatusBarView.findViewById(R.id.battery),
+                            mConfigurationController,
+                            mTunerService,
+                            mBroadcastDispatcher,
+                            mMainThreadHandler,
+                            mContext.getContentResolver()
+                    );
+                    mBatteryMeterViewController.init();
 
                     // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
                     // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
@@ -1220,7 +1282,6 @@
 
         mHeadsUpManager.setup(mVisualStabilityManager);
         mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView);
-        mHeadsUpManager.addListener(this);
         mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
         mHeadsUpManager.addListener(mVisualStabilityManager);
         mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
@@ -1263,13 +1324,11 @@
         ScrimView notificationsScrim = mNotificationShadeWindowView
                 .findViewById(R.id.scrim_notifications);
         ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front);
-        ScrimView scrimForBubble = mBubblesManagerOptional.isPresent()
-                ? mBubblesManagerOptional.get().getScrimForBubble() : null;
 
         mScrimController.setScrimVisibleListener(scrimsVisible -> {
             mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible);
         });
-        mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront, scrimForBubble);
+        mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
 
         mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
         mLightRevealScrim.setRevealAmountListener(
@@ -1319,7 +1378,7 @@
                 QS qs = (QS) f;
                 if (qs instanceof QSFragment) {
                     mQSPanelController = ((QSFragment) qs).getQSPanelController();
-                    mQSPanelController.setBrightnessMirror(mBrightnessMirrorController);
+                    ((QSFragment) qs).setBrightnessMirrorController(mBrightnessMirrorController);
                 }
             });
         }
@@ -1350,14 +1409,11 @@
             });
         }
 
-        if (!mPowerManager.isScreenOn()) {
+        if (!mPowerManager.isInteractive()) {
             mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
         }
         mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
-                "GestureWakeLock");
-        mVibrator = mContext.getSystemService(Vibrator.class);
-        mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
-                mVibrator, context.getResources());
+                "sysui:GestureWakeLock");
 
         // receive broadcasts
         registerBroadcastReceiver();
@@ -1366,7 +1422,7 @@
         if (DEBUG_MEDIA_FAKE_ARTWORK) {
             demoFilter.addAction(ACTION_FAKE_ARTWORK);
         }
-        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
+        mContext.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
                 android.Manifest.permission.DUMP, null);
 
         // listen for USER_SETUP_COMPLETE setting (per-user)
@@ -1600,6 +1656,20 @@
 
         mAuthRippleController = statusBarComponent.getAuthRippleController();
         mAuthRippleController.init();
+
+        mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+
+        mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+
+        // Listen for demo mode changes
+        mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode());
+
+        if (mCommandQueueCallbacks != null) {
+            mCommandQueue.removeCallback(mCommandQueueCallbacks);
+        }
+        mCommandQueueCallbacks = statusBarComponent.getStatusBarCommandQueueCallbacks();
+        // Connect in to the status bar manager service
+        mCommandQueue.addCallback(mCommandQueueCallbacks);
     }
 
     protected void startKeyguard() {
@@ -1649,7 +1719,7 @@
         Trace.endSection();
     }
 
-    protected View getStatusBarView() {
+    protected PhoneStatusBarView getStatusBarView() {
         return mStatusBarView;
     }
 
@@ -1711,7 +1781,7 @@
      * If the user switcher is simple then disable QS during setup because
      * the user intends to use the lock screen user switcher, QS in not needed.
      */
-    private void updateQsExpansionEnabled() {
+    void updateQsExpansionEnabled() {
         final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
                 && (mUserSetup || mUserSwitcherController == null
                         || !mUserSwitcherController.isSimpleUserSwitcher())
@@ -1727,22 +1797,6 @@
         return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
     }
 
-    public void addQsTile(ComponentName tile) {
-        if (mQSPanelController != null && mQSPanelController.getHost() != null) {
-            mQSPanelController.getHost().addTile(tile);
-        }
-    }
-
-    public void remQsTile(ComponentName tile) {
-        if (mQSPanelController != null && mQSPanelController.getHost() != null) {
-            mQSPanelController.getHost().removeTile(tile);
-        }
-    }
-
-    public void clickTile(ComponentName tile) {
-        mQSPanelController.clickTile(tile);
-    }
-
     /**
      * Request a notification update
      * @param reason why we're requesting a notification update
@@ -1768,94 +1822,6 @@
                 && mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
     }
 
-    /**
-     * State is one or more of the DISABLE constants from StatusBarManager.
-     */
-    @Override
-    public void disable(int displayId, int state1, int state2, boolean animate) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
-
-        animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
-        final int old1 = mDisabled1;
-        final int diff1 = state1 ^ old1;
-        mDisabled1 = state1;
-
-        final int old2 = mDisabled2;
-        final int diff2 = state2 ^ old2;
-        mDisabled2 = state2;
-
-        if (DEBUG) {
-            Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
-                old1, state1, diff1));
-            Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
-                old2, state2, diff2));
-        }
-
-        StringBuilder flagdbg = new StringBuilder();
-        flagdbg.append("disable<");
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND))                ? 'E' : 'e');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_EXPAND))                ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? 'I' : 'i');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? 'A' : 'a');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO))           ? 'S' : 's');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO))           ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK))                  ? 'B' : 'b');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_BACK))                  ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME))                  ? 'H' : 'h');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_HOME))                  ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT))                ? 'R' : 'r');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_RECENT))                ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK))                 ? 'C' : 'c');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_CLOCK))                 ? '!' : ' ');
-        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH))                ? 'S' : 's');
-        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SEARCH))                ? '!' : ' ');
-        flagdbg.append("> disable2<");
-        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? 'Q' : 'q');
-        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? '!' : ' ');
-        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS))         ? 'I' : 'i');
-        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_SYSTEM_ICONS))         ? '!' : ' ');
-        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))   ? 'N' : 'n');
-        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))   ? '!' : ' ');
-        flagdbg.append('>');
-        Log.d(TAG, flagdbg.toString());
-
-        if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
-                mShadeController.animateCollapsePanels();
-            }
-        }
-
-        if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
-            if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
-                // close recents if it's visible
-                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
-                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
-            }
-        }
-
-        if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
-            if (areNotificationAlertsDisabled()) {
-                mHeadsUpManager.releaseAllImmediately();
-            }
-        }
-
-        if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
-            updateQsExpansionEnabled();
-        }
-
-        if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
-            updateQsExpansionEnabled();
-            if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
-                mShadeController.animateCollapsePanels();
-            }
-        }
-    }
-
     boolean areNotificationAlertsDisabled() {
         return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
     }
@@ -1920,70 +1886,6 @@
         logStateToEventlog();
     }
 
-    @Override
-    public void onUnlockedChanged() {
-        updateKeyguardState();
-        logStateToEventlog();
-    }
-
-    @Override
-    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
-        if (inPinnedMode) {
-            mNotificationShadeWindowController.setHeadsUpShowing(true);
-            mStatusBarWindowController.setForceStatusBarVisible(true);
-            if (mNotificationPanelViewController.isFullyCollapsed()) {
-                // We need to ensure that the touchable region is updated before the window will be
-                // resized, in order to not catch any touches. A layout will ensure that
-                // onComputeInternalInsets will be called and after that we can resize the layout. Let's
-                // make sure that the window stays small for one frame until the touchableRegion is set.
-                mNotificationPanelViewController.getView().requestLayout();
-                mNotificationShadeWindowController.setForceWindowCollapsed(true);
-                mNotificationPanelViewController.getView().post(() -> {
-                    mNotificationShadeWindowController.setForceWindowCollapsed(false);
-                });
-            }
-        } else {
-            boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
-                    && mState == StatusBarState.KEYGUARD;
-            if (!mNotificationPanelViewController.isFullyCollapsed()
-                    || mNotificationPanelViewController.isTracking() || bypassKeyguard) {
-                // We are currently tracking or is open and the shade doesn't need to be kept
-                // open artificially.
-                mNotificationShadeWindowController.setHeadsUpShowing(false);
-                if (bypassKeyguard) {
-                    mStatusBarWindowController.setForceStatusBarVisible(false);
-                }
-            } else {
-                // we need to keep the panel open artificially, let's wait until the animation
-                // is finished.
-                mHeadsUpManager.setHeadsUpGoingAway(true);
-                mNotificationPanelViewController.runAfterAnimationFinished(() -> {
-                    if (!mHeadsUpManager.hasPinnedHeadsUp()) {
-                        mNotificationShadeWindowController.setHeadsUpShowing(false);
-                        mHeadsUpManager.setHeadsUpGoingAway(false);
-                    }
-                    mRemoteInputManager.onPanelCollapsed();
-                });
-            }
-        }
-    }
-
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
-        if (mStatusBarStateController.isDozing() && isHeadsUp) {
-            entry.setPulseSuppressed(false);
-            mDozeServiceHost.fireNotificationPulse(entry);
-            if (mDozeServiceHost.isPulsing()) {
-                mDozeScrimController.cancelPendingPulseTimeout();
-            }
-        }
-        if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
-            // There are no longer any notifications to show.  We should end the pulse now.
-            mDozeScrimController.pulseOutNow();
-        }
-    }
-
     public void setPanelExpanded(boolean isExpanded) {
         if (mPanelExpanded != isExpanded) {
             mNotificationLogger.onPanelExpandedChanged(isExpanded);
@@ -2016,11 +1918,6 @@
         return mNotificationPanelViewController.hideStatusBarIconsWhenExpanded();
     }
 
-    @Override
-    public void onColorsChanged(ColorExtractor extractor, int which) {
-        updateTheme();
-    }
-
     @Nullable
     public View getAmbientIndicationContainer() {
         return mAmbientIndicationContainer;
@@ -2056,7 +1953,7 @@
      *
      * @param animate should the change of the icons be animated.
      */
-    private void updateHideIconsForBouncer(boolean animate) {
+    void updateHideIconsForBouncer(boolean animate) {
         boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
                 && (mStatusBarWindowHidden || mBouncerShowing);
         boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
@@ -2170,15 +2067,14 @@
         mState = state;
     }
 
-    @VisibleForTesting
-    void setUserSetupForTest(boolean userSetup) {
-        mUserSetup = userSetup;
-    }
-
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
     protected class H extends Handler {
+        H() {
+            super(Looper.myLooper());
+        }
+
         @Override
         public void handleMessage(Message m) {
             switch (m.what) {
@@ -2190,10 +2086,10 @@
                     break;
                 // End old BaseStatusBar.H handling.
                 case MSG_OPEN_NOTIFICATION_PANEL:
-                    animateExpandNotificationsPanel();
+                    mCommandQueueCallbacks.animateExpandNotificationsPanel();
                     break;
                 case MSG_OPEN_SETTINGS_PANEL:
-                    animateExpandSettingsPanel((String) m.obj);
+                    mCommandQueueCallbacks.animateExpandSettingsPanel((String) m.obj);
                     break;
                 case MSG_CLOSE_PANELS:
                     mShadeController.animateCollapsePanels();
@@ -2225,59 +2121,6 @@
         mHeadsUpManager.releaseAllImmediately();
     }
 
-    /**
-     * Called for system navigation gestures. First action opens the panel, second opens
-     * settings. Down action closes the entire panel.
-     */
-    @Override
-    public void handleSystemKey(int key) {
-        if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
-        if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
-                || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
-            return;
-        }
-
-        // Panels are not available in setup
-        if (!mUserSetup) return;
-
-        if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
-            mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
-            mNotificationPanelViewController.collapse(
-                    false /* delayed */, 1.0f /* speedUpFactor */);
-        } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
-            mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
-            if (mNotificationPanelViewController.isFullyCollapsed()) {
-                if (mVibrateOnOpening) {
-                    mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
-                }
-                mNotificationPanelViewController.expand(true /* animate */);
-                mStackScroller.setWillExpand(true);
-                mHeadsUpManager.unpinAll(true /* userUnpinned */);
-                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
-            } else if (!mNotificationPanelViewController.isInSettings()
-                    && !mNotificationPanelViewController.isExpanding()) {
-                mNotificationPanelViewController.flingSettings(0 /* velocity */,
-                        NotificationPanelView.FLING_EXPAND);
-                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
-            }
-        }
-
-    }
-
-    @Override
-    public void showPinningEnterExitToast(boolean entering) {
-        if (getNavigationBarView() != null) {
-            getNavigationBarView().showPinningEnterExitToast(entering);
-        }
-    }
-
-    @Override
-    public void showPinningEscapeToast() {
-        if (getNavigationBarView() != null) {
-            getNavigationBarView().showPinningEscapeToast();
-        }
-    }
-
     void makeExpandedVisible(boolean force) {
         if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
         if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
@@ -2308,21 +2151,6 @@
         mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
     }
 
-    @Override
-    public void togglePanel() {
-        if (mPanelExpanded) {
-            mShadeController.animateCollapsePanels();
-        } else {
-            animateExpandNotificationsPanel();
-        }
-    }
-
-    @Override
-    public void animateCollapsePanels(int flags, boolean force) {
-        mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
-                1.0f /* speedUpFactor */);
-    }
-
     /**
      * Called by {@link ShadeController} when it calls
      * {@link ShadeController#animateCollapsePanels(int, boolean, boolean, float)}.
@@ -2357,36 +2185,6 @@
         }
     }
 
-    @Override
-    public void animateExpandNotificationsPanel() {
-        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if (!mCommandQueue.panelsEnabled()) {
-            return ;
-        }
-
-        mNotificationPanelViewController.expandWithoutQs();
-
-        if (false) postStartTracing();
-    }
-
-    @Override
-    public void animateExpandSettingsPanel(@Nullable String subPanel) {
-        if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
-        if (!mCommandQueue.panelsEnabled()) {
-            return;
-        }
-
-        // Settings are not available in setup
-        if (!mUserSetup) return;
-
-        if (subPanel != null) {
-            mQSPanelController.openDetails(subPanel);
-        }
-        mNotificationPanelViewController.expandWithQs();
-
-        if (false) postStartTracing();
-    }
-
     public void animateCollapseQuickSettings() {
         if (mState == StatusBarState.SHADE) {
             mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
@@ -2466,11 +2264,7 @@
             final boolean upOrCancel =
                     event.getAction() == MotionEvent.ACTION_UP ||
                     event.getAction() == MotionEvent.ACTION_CANCEL;
-            if (upOrCancel && !mExpandedVisible) {
-                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-            } else {
-                setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
-            }
+            setInteracting(StatusBarManager.WINDOW_STATUS_BAR, !upOrCancel || mExpandedVisible);
         }
         return false;
     }
@@ -2487,63 +2281,7 @@
         return mBiometricUnlockController;
     }
 
-    @Override // CommandQueue
-    public void setWindowState(
-            int displayId, @WindowType int window, @WindowVisibleState int state) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        boolean showing = state == WINDOW_STATE_SHOWING;
-        if (mNotificationShadeWindowView != null
-                && window == StatusBarManager.WINDOW_STATUS_BAR
-                && mStatusBarWindowState != state) {
-            mStatusBarWindowState = state;
-            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
-            if (mStatusBarView != null) {
-                if (!showing && mState == StatusBarState.SHADE) {
-                    mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
-                            1.0f /* speedUpFactor */);
-                }
-                mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
-                updateHideIconsForBouncer(false /* animate */);
-            }
-        }
-
-        updateBubblesVisibility();
-    }
-
-    @Override
-    public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
-            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
-            @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        boolean barModeChanged = false;
-        if (mAppearance != appearance) {
-            mAppearance = appearance;
-            barModeChanged = updateBarMode(barMode(mTransientShown, appearance));
-        }
-        mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
-                mStatusBarMode, navbarColorManagedByIme);
-
-        updateBubblesVisibility();
-        mStatusBarStateController.setSystemBarAttributes(
-                appearance, behavior, requestedVisibilities, packageName);
-    }
-
-    @Override
-    public void showTransient(int displayId, @InternalInsetsType int[] types) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        if (!containsType(types, ITYPE_STATUS_BAR)) {
-            return;
-        }
-        showTransientUnchecked();
-    }
-
-    private void showTransientUnchecked() {
+    void showTransientUnchecked() {
         if (!mTransientShown) {
             mTransientShown = true;
             mNoAnimationOnNextBarModeChange = true;
@@ -2551,18 +2289,8 @@
         }
     }
 
-    @Override
-    public void abortTransient(int displayId, @InternalInsetsType int[] types) {
-        if (displayId != mDisplayId) {
-            return;
-        }
-        if (!containsType(types, ITYPE_STATUS_BAR)) {
-            return;
-        }
-        clearTransient();
-    }
 
-    private void clearTransient() {
+    void clearTransient() {
         if (mTransientShown) {
             mTransientShown = false;
             handleTransientChanged();
@@ -2604,8 +2332,7 @@
         }
     }
 
-    @Override
-    public void showWirelessChargingAnimation(int batteryLevel) {
+    protected void showWirelessChargingAnimation(int batteryLevel) {
         showChargingAnimation(batteryLevel, UNKNOWN_BATTERY_LEVEL, 0);
     }
 
@@ -2626,11 +2353,6 @@
                 }, false, sUiEventLogger).show(animationDelay);
     }
 
-    @Override
-    public void onRecentsAnimationStateChanged(boolean running) {
-        setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
-    }
-
     protected BarTransitions getStatusBarTransitions() {
         return mNotificationShadeWindowViewController.getBarTransitions();
     }
@@ -2650,13 +2372,11 @@
     }
 
     /** Temporarily hides Bubbles if the status bar is hidden. */
-    private void updateBubblesVisibility() {
-        if (mBubblesOptional.isPresent()) {
-            mBubblesOptional.get().onStatusBarVisibilityChanged(
-                    mStatusBarMode != MODE_LIGHTS_OUT
-                            && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
-                            && !mStatusBarWindowHidden);
-        }
+    void updateBubblesVisibility() {
+        mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
+                mStatusBarMode != MODE_LIGHTS_OUT
+                        && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
+                        && !mStatusBarWindowHidden));
     }
 
     void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
@@ -2740,7 +2460,7 @@
             mNotificationPanelViewController.dump(fd, pw, args);
         }
         pw.println("  mStackScroller: ");
-        if (mStackScroller instanceof Dumpable) {
+        if (mStackScroller != null) {
             pw.print  ("      ");
             ((Dumpable) mStackScroller).dump(fd, pw, args);
         }
@@ -2773,19 +2493,6 @@
 
         mNotificationsController.dump(fd, pw, args, DUMPTRUCK);
 
-        if (DUMPTRUCK) {
-            if (false) {
-                pw.println("see the logcat for a dump of the views we have created.");
-                // must happen on ui thread
-                mHandler.post(() -> {
-                    mStatusBarView.getLocationOnScreen(mAbsPos);
-                    Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
-                            ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
-                    mStatusBarView.debug();
-                });
-            }
-        }
-
         if (DEBUG_GESTURES) {
             pw.print("  status bar gestures: ");
             mGestureRec.dump(fd, pw, args);
@@ -2816,7 +2523,7 @@
         pw.println("   Insecure camera: " + CameraIntents.getInsecureCameraIntent(mContext));
         pw.println("   Secure camera: " + CameraIntents.getSecureCameraIntent(mContext));
         pw.println("   Override package: "
-                + String.valueOf(CameraIntents.getOverrideCameraPackage(mContext)));
+                + CameraIntents.getOverrideCameraPackage(mContext));
     }
 
     public static void dumpBarTransitions(
@@ -2877,7 +2584,7 @@
         startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
     }
 
-    private void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
+    void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
             final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
             final Callback callback, int flags,
             @Nullable ActivityLaunchAnimator.Controller animationController) {
@@ -2922,7 +2629,7 @@
                             options.setRotationAnimationHint(
                                     WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
                         }
-                        if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
+                        if (intent.getAction().equals(Settings.Panel.ACTION_VOLUME)) {
                             // Settings Panel is implemented as activity(not a dialog), so
                             // underlying app is paused and may enter picture-in-picture mode
                             // as a result.
@@ -3021,7 +2728,7 @@
                             && mStatusBarKeyguardViewManager.isOccluded()) {
                         mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
                     } else {
-                        AsyncTask.execute(runnable);
+                        mHandler.post(runnable);
                     }
                 }
                 if (dismissShade) {
@@ -3304,37 +3011,6 @@
                 | ((currentlyInsecure ? 1 : 0) << 12);
     }
 
-    //
-    // tracing
-    //
-
-    void postStartTracing() {
-        mHandler.postDelayed(mStartTracing, 3000);
-    }
-
-    void vibrate() {
-        android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
-                Context.VIBRATOR_SERVICE);
-        vib.vibrate(250, VIBRATION_ATTRIBUTES);
-    }
-
-    final Runnable mStartTracing = new Runnable() {
-        @Override
-        public void run() {
-            vibrate();
-            SystemClock.sleep(250);
-            Log.d(TAG, "startTracing");
-            android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
-            mHandler.postDelayed(mStopTracing, 10000);
-        }
-    };
-
-    final Runnable mStopTracing = () -> {
-        android.os.Debug.stopMethodTracing();
-        Log.d(TAG, "stopTracing");
-        vibrate();
-    };
-
     @Override
     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
         mHandler.post(() -> {
@@ -3375,82 +3051,6 @@
                 delay);
     }
 
-    @Override
-    public List<String> demoCommands() {
-        List<String> s = new ArrayList<>();
-        s.add(DemoMode.COMMAND_BARS);
-        s.add(DemoMode.COMMAND_CLOCK);
-        s.add(DemoMode.COMMAND_OPERATOR);
-        return s;
-    }
-
-    @Override
-    public void onDemoModeStarted() {
-        // Must send this message to any view that we delegate to via dispatchDemoCommandToView
-        dispatchDemoModeStartedToView(R.id.clock);
-        dispatchDemoModeStartedToView(R.id.operator_name);
-    }
-
-    @Override
-    public void onDemoModeFinished() {
-        dispatchDemoModeFinishedToView(R.id.clock);
-        dispatchDemoModeFinishedToView(R.id.operator_name);
-        checkBarModes();
-    }
-
-    @Override
-    public void dispatchDemoCommand(String command, @NonNull Bundle args) {
-        if (command.equals(COMMAND_CLOCK)) {
-            dispatchDemoCommandToView(command, args, R.id.clock);
-        }
-        if (command.equals(COMMAND_BARS)) {
-            String mode = args.getString("mode");
-            int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
-                    "translucent".equals(mode) ? MODE_TRANSLUCENT :
-                    "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
-                    "transparent".equals(mode) ? MODE_TRANSPARENT :
-                    "warning".equals(mode) ? MODE_WARNING :
-                    -1;
-            if (barMode != -1) {
-                boolean animate = true;
-                if (mNotificationShadeWindowController != null
-                        && mNotificationShadeWindowViewController.getBarTransitions() != null) {
-                    mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
-                            barMode, animate);
-                }
-                mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
-            }
-        }
-        if (command.equals(COMMAND_OPERATOR)) {
-            dispatchDemoCommandToView(command, args, R.id.operator_name);
-        }
-    }
-
-    //TODO: these should have controllers, and this method should be removed
-    private void dispatchDemoCommandToView(String command, Bundle args, int id) {
-        if (mStatusBarView == null) return;
-        View v = mStatusBarView.findViewById(id);
-        if (v instanceof DemoModeCommandReceiver) {
-            ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
-        }
-    }
-
-    private void dispatchDemoModeStartedToView(int id) {
-        if (mStatusBarView == null) return;
-        View v = mStatusBarView.findViewById(id);
-        if (v instanceof DemoModeCommandReceiver) {
-            ((DemoModeCommandReceiver) v).onDemoModeStarted();
-        }
-    }
-
-    private void dispatchDemoModeFinishedToView(int id) {
-        if (mStatusBarView == null) return;
-        View v = mStatusBarView.findViewById(id);
-        if (v instanceof DemoModeCommandReceiver) {
-            ((DemoModeCommandReceiver) v).onDemoModeFinished();
-        }
-    }
-
     public void showKeyguard() {
         mStatusBarStateController.setKeyguardRequested(true);
         mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
@@ -3591,7 +3191,7 @@
      */
     public void animateKeyguardUnoccluding() {
         mNotificationPanelViewController.setExpandedFraction(0f);
-        animateExpandNotificationsPanel();
+        mCommandQueueCallbacks.animateExpandNotificationsPanel();
     }
 
     /**
@@ -3762,7 +3362,7 @@
 
     /**
      * While IME is active and a BACK event is detected, check with
-     * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme(KeyEvent)} to see if the event
+     * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
      * should be handled before routing to IME, in order to prevent the user having to hit back
      * twice to exit bouncer.
      */
@@ -4088,7 +3688,8 @@
 
                 // This gets executed before we will show Keyguard, so post it in order that the state
                 // is correct.
-                mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
+                mHandler.post(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
+                        mLastCameraLaunchSource));
             }
 
             if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
@@ -4096,7 +3697,8 @@
 
                 // This gets executed before we will show Keyguard, so post it in order that the
                 // state is correct.
-                mHandler.post(() -> onEmergencyActionLaunchGestureDetected());
+                mHandler.post(
+                        () -> mCommandQueueCallbacks.onEmergencyActionLaunchGestureDetected());
             }
             updateIsKeyguard();
         }
@@ -4209,36 +3811,6 @@
         return mWakefulnessLifecycle.getWakefulness();
     }
 
-    private void vibrateForCameraGesture() {
-        // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
-        mVibrator.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES);
-    }
-
-    private static VibrationEffect getCameraGestureVibrationEffect(Vibrator vibrator,
-            Resources resources) {
-        if (vibrator.areAllPrimitivesSupported(
-                VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
-                VibrationEffect.Composition.PRIMITIVE_CLICK)) {
-            return VibrationEffect.startComposition()
-                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
-                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
-                    .compose();
-        }
-        if (vibrator.hasAmplitudeControl()) {
-            return VibrationEffect.createWaveform(
-                    CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
-                    CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
-                    /* repeat= */ -1);
-        }
-
-        int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
-        long[] timings = new long[pattern.length];
-        for (int i = 0; i < pattern.length; i++) {
-            timings[i] = pattern[i];
-        }
-        return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
-    }
-
     /**
      * @return true if the screen is currently fully off, i.e. has finished turning off and has
      * since not started turning on.
@@ -4247,139 +3819,11 @@
         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
     }
 
-    @Override
-    public void showScreenPinningRequest(int taskId) {
-        if (mKeyguardStateController.isShowing()) {
-            // Don't allow apps to trigger this from keyguard.
-            return;
-        }
-        // Show screen pinning request, since this comes from an app, show 'no thanks', button.
-        showScreenPinningRequest(taskId, true);
-    }
-
     public void showScreenPinningRequest(int taskId, boolean allowCancel) {
         mScreenPinningRequest.showPrompt(taskId, allowCancel);
     }
 
-    @Override
-    public void appTransitionCancelled(int displayId) {
-        if (displayId == mDisplayId) {
-            mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
-        }
-    }
-
-    @Override
-    public void appTransitionFinished(int displayId) {
-        if (displayId == mDisplayId) {
-            mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
-        }
-    }
-
-    @Override
-    public void onCameraLaunchGestureDetected(int source) {
-        mLastCameraLaunchSource = source;
-        if (isGoingToSleep()) {
-            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
-            mLaunchCameraOnFinishedGoingToSleep = true;
-            return;
-        }
-        if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
-            if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now");
-            return;
-        }
-        if (!mDeviceInteractive) {
-            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
-                    "com.android.systemui:CAMERA_GESTURE");
-        }
-        vibrateForCameraGesture();
-
-        if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
-            Log.v(TAG, "Camera launch");
-            mKeyguardUpdateMonitor.onCameraLaunched();
-        }
-
-        if (!mStatusBarKeyguardViewManager.isShowing()) {
-            final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
-            startActivityDismissingKeyguard(cameraIntent,
-                    false /* onlyProvisioned */, true /* dismissShade */,
-                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
-                    null /* animationController */);
-        } else {
-            if (!mDeviceInteractive) {
-                // Avoid flickering of the scrim when we instant launch the camera and the bouncer
-                // comes on.
-                mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
-            }
-            if (isWakingUpOrAwake()) {
-                if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
-                if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                    mStatusBarKeyguardViewManager.reset(true /* hide */);
-                }
-                mNotificationPanelViewController.launchCamera(
-                        mDeviceInteractive /* animate */, source);
-                updateScrimController();
-            } else {
-                // We need to defer the camera launch until the screen comes on, since otherwise
-                // we will dismiss us too early since we are waiting on an activity to be drawn and
-                // incorrectly get notified because of the screen on event (which resumes and pauses
-                // some activities)
-                if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
-                mLaunchCameraWhenFinishedWaking = true;
-            }
-        }
-    }
-
-    @Override
-    public void onEmergencyActionLaunchGestureDetected() {
-        Intent emergencyIntent = getEmergencyActionIntent();
-
-        if (emergencyIntent == null) {
-            Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
-            return;
-        }
-
-        if (isGoingToSleep()) {
-            mLaunchEmergencyActionOnFinishedGoingToSleep = true;
-            return;
-        }
-
-        if (!mDeviceInteractive) {
-            mPowerManager.wakeUp(SystemClock.uptimeMillis(),
-                    PowerManager.WAKE_REASON_GESTURE,
-                    "com.android.systemui:EMERGENCY_GESTURE");
-        }
-        // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
-        // app-side haptic experimentation.
-
-        if (!mStatusBarKeyguardViewManager.isShowing()) {
-            startActivityDismissingKeyguard(emergencyIntent,
-                    false /* onlyProvisioned */, true /* dismissShade */,
-                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
-                    null /* animationController */);
-            return;
-        }
-
-        if (!mDeviceInteractive) {
-            // Avoid flickering of the scrim when we instant launch the camera and the bouncer
-            // comes on.
-            mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
-        }
-
-        if (isWakingUpOrAwake()) {
-            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                mStatusBarKeyguardViewManager.reset(true /* hide */);
-            }
-            mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
-            return;
-        }
-        // We need to defer the emergency action launch until the screen comes on, since otherwise
-        // we will dismiss us too early since we are waiting on an activity to be drawn and
-        // incorrectly get notified because of the screen on event (which resumes and pauses
-        // some activities)
-        mLaunchEmergencyActionWhenFinishedWaking = true;
-    }
-
-    private @Nullable Intent getEmergencyActionIntent() {
+    @Nullable Intent getEmergencyActionIntent() {
         Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
         PackageManager pm = mContext.getPackageManager();
         List<ResolveInfo> emergencyActivities = pm.queryIntentActivities(emergencyIntent,
@@ -4437,16 +3881,11 @@
         return true;
     }
 
-    private boolean isGoingToSleep() {
+    boolean isGoingToSleep() {
         return mWakefulnessLifecycle.getWakefulness()
                 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
     }
 
-    private boolean isWakingUpOrAwake() {
-        return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
-                || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
-    }
-
     public void notifyBiometricAuthModeChanged() {
         mDozeServiceHost.updateDozing();
         updateScrimController();
@@ -4501,8 +3940,6 @@
             mScrimController.transitionTo(ScrimState.AOD);
         } else if (mIsKeyguard && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
-        } else if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
-            mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback);
         } else {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         }
@@ -4599,10 +4036,6 @@
         mNotificationsController.setNotificationSnoozed(sbn, snoozeOption);
     }
 
-    @Override
-    public void toggleSplitScreen() {
-        toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
-    }
 
     public void awakenDreams() {
         mUiBgExecutor.execute(() -> {
@@ -4614,46 +4047,6 @@
         });
     }
 
-    @Override
-    public void preloadRecentApps() {
-        int msg = MSG_PRELOAD_RECENT_APPS;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    @Override
-    public void cancelPreloadRecentApps() {
-        int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    @Override
-    public void dismissKeyboardShortcutsMenu() {
-        int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    @Override
-    public void toggleKeyboardShortcutsMenu(int deviceId) {
-        int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
-        mHandler.removeMessages(msg);
-        mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
-    }
-
-    @Override
-    public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
-        mTopHidesStatusBar = topAppHidesStatusBar;
-        if (!topAppHidesStatusBar && mWereIconsJustHidden) {
-            // Immediately update the icon hidden state, since that should only apply if we're
-            // staying fullscreen.
-            mWereIconsJustHidden = false;
-            mCommandQueue.recomputeDisableFlags(mDisplayId, true);
-        }
-        updateHideIconsForBouncer(true /* animate */);
-    }
-
     protected void toggleKeyboardShortcuts(int deviceId) {
         KeyboardShortcuts.toggle(mContext, deviceId);
     }
@@ -4915,34 +4308,19 @@
         }
         return mStatusBarKeyguardViewManager.isSecure();
     }
-
-    @Override
-    public void showAssistDisclosure() {
-        mAssistManagerLazy.get().showDisclosure();
-    }
-
     public NotificationPanelViewController getPanelController() {
         return mNotificationPanelViewController;
     }
-
-    @Override
-    public void startAssist(Bundle args) {
-        mAssistManagerLazy.get().startAssist(args);
-    }
     // End Extra BaseStatusBarMethods.
 
     public NotificationGutsManager getGutsManager() {
         return mGutsManager;
     }
 
-    private boolean isTransientShown() {
+    boolean isTransientShown() {
         return mTransientShown;
     }
 
-    @Override
-    public void suppressAmbientDisplay(boolean suppressed) {
-        mDozeServiceHost.setDozeSuppressed(suppressed);
-    }
 
     public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
         mExpansionChangedListeners.add(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
new file mode 100644
index 0000000..95f2d0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.windowStateToString;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.containsType;
+
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+
+import android.annotation.Nullable;
+import android.app.StatusBarManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.AudioAttributes;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.Log;
+import android.util.Slog;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
+import android.view.KeyEvent;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.AppearanceRegion;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.qs.QSPanelController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
+    private final StatusBar mStatusBar;
+    private final Context mContext;
+    private final ShadeController mShadeController;
+    private final CommandQueue mCommandQueue;
+    private final NotificationPanelViewController mNotificationPanelViewController;
+    private final Optional<LegacySplitScreen> mSplitScreenOptional;
+    private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+    private final MetricsLogger mMetricsLogger;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final KeyguardStateController mKeyguardStateController;
+    private final HeadsUpManager mHeadsUpManager;
+    private final WakefulnessLifecycle mWakefulnessLifecycle;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final AssistManager mAssistManager;
+    private final DozeServiceHost mDozeServiceHost;
+    private final SysuiStatusBarStateController mStatusBarStateController;
+    private final NotificationShadeWindowView mNotificationShadeWindowView;
+    private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+    private final PowerManager mPowerManager;
+    private final VibratorHelper mVibratorHelper;
+    private final Optional<Vibrator> mVibratorOptional;
+    private final LightBarController mLightBarController;
+    private final int mDisplayId;
+    private final boolean mVibrateOnOpening;
+    private final VibrationEffect mCameraLaunchGestureVibrationEffect;
+
+
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
+
+    @Inject
+    StatusBarCommandQueueCallbacks(
+            StatusBar statusBar,
+            Context context,
+            @Main Resources resources,
+            ShadeController shadeController,
+            CommandQueue commandQueue,
+            NotificationPanelViewController notificationPanelViewController,
+            Optional<LegacySplitScreen> splitScreenOptional,
+            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+            MetricsLogger metricsLogger,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            KeyguardStateController keyguardStateController,
+            HeadsUpManager headsUpManager,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            DeviceProvisionedController deviceProvisionedController,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            AssistManager assistManager,
+            DozeServiceHost dozeServiceHost,
+            SysuiStatusBarStateController statusBarStateController,
+            NotificationShadeWindowView notificationShadeWindowView,
+            NotificationStackScrollLayoutController notificationStackScrollLayoutController,
+            PowerManager powerManager,
+            VibratorHelper vibratorHelper,
+            Optional<Vibrator> vibratorOptional,
+            LightBarController lightBarController,
+            @DisplayId int displayId) {
+
+        mStatusBar = statusBar;
+        mContext = context;
+        mShadeController = shadeController;
+        mCommandQueue = commandQueue;
+        mNotificationPanelViewController = notificationPanelViewController;
+        mSplitScreenOptional = splitScreenOptional;
+        mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
+        mMetricsLogger = metricsLogger;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mKeyguardStateController = keyguardStateController;
+        mHeadsUpManager = headsUpManager;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mAssistManager = assistManager;
+        mDozeServiceHost = dozeServiceHost;
+        mStatusBarStateController = statusBarStateController;
+        mNotificationShadeWindowView = notificationShadeWindowView;
+        mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
+        mPowerManager = powerManager;
+        mVibratorHelper = vibratorHelper;
+        mVibratorOptional = vibratorOptional;
+        mLightBarController = lightBarController;
+        mDisplayId = displayId;
+
+        mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
+        mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
+                mVibratorOptional, resources);
+    }
+
+    @Override
+    public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        if (!containsType(types, ITYPE_STATUS_BAR)) {
+            return;
+        }
+        mStatusBar.clearTransient();
+    }
+
+    @Override
+    public void addQsTile(ComponentName tile) {
+        QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+        if (qsPanelController != null && qsPanelController.getHost() != null) {
+            qsPanelController.getHost().addTile(tile);
+        }
+    }
+
+    @Override
+    public void remQsTile(ComponentName tile) {
+        QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+        if (qsPanelController != null && qsPanelController.getHost() != null) {
+            qsPanelController.getHost().removeTile(tile);
+        }
+    }
+
+    @Override
+    public void clickTile(ComponentName tile) {
+        QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+        if (qsPanelController != null) {
+            qsPanelController.clickTile(tile);
+        }
+    }
+
+    @Override
+    public void animateCollapsePanels(int flags, boolean force) {
+        mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
+                1.0f /* speedUpFactor */);
+    }
+
+    @Override
+    public void animateExpandNotificationsPanel() {
+        if (StatusBar.SPEW) {
+            Log.d(StatusBar.TAG,
+                    "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+        }
+        if (!mCommandQueue.panelsEnabled()) {
+            return;
+        }
+
+        mNotificationPanelViewController.expandWithoutQs();
+    }
+
+    @Override
+    public void animateExpandSettingsPanel(@Nullable String subPanel) {
+        if (StatusBar.SPEW) {
+            Log.d(StatusBar.TAG,
+                    "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+        }
+        if (!mCommandQueue.panelsEnabled()) {
+            return;
+        }
+
+        // Settings are not available in setup
+        if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+
+        QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+        if (subPanel != null && qsPanelController != null) {
+            qsPanelController.openDetails(subPanel);
+        }
+        mNotificationPanelViewController.expandWithQs();
+    }
+
+    @Override
+    public void appTransitionCancelled(int displayId) {
+        if (displayId == mDisplayId) {
+            mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+        }
+    }
+
+    @Override
+    public void appTransitionFinished(int displayId) {
+        if (displayId == mDisplayId) {
+            mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+        }
+    }
+
+    @Override
+    public void preloadRecentApps() {
+        mStatusBar.resetHandlerMsg(StatusBar.MSG_PRELOAD_RECENT_APPS);
+    }
+
+    @Override
+    public void cancelPreloadRecentApps() {
+        mStatusBar.resetHandlerMsg(StatusBar.MSG_CANCEL_PRELOAD_RECENT_APPS);
+    }
+
+    @Override
+    public void dismissKeyboardShortcutsMenu() {
+        mStatusBar.resetHandlerMsg(StatusBar.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU);
+    }
+    /**
+     * State is one or more of the DISABLE constants from StatusBarManager.
+     */
+    @Override
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
+        final int old1 = mStatusBar.getDisabled1();
+        final int diff1 = state1 ^ old1;
+        mStatusBar.setDisabled1(state1);
+
+        final int old2 = mStatusBar.getDisabled2();
+        final int diff2 = state2 ^ old2;
+        mStatusBar.setDisabled2(state2);
+
+        if (StatusBar.DEBUG) {
+            Log.d(StatusBar.TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
+                    old1, state1, diff1));
+            Log.d(StatusBar.TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
+                    old2, state2, diff2));
+        }
+
+        StringBuilder flagdbg = new StringBuilder();
+        flagdbg.append("disable<");
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND))               ? 'E' : 'e');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_EXPAND))               ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS))   ? 'I' : 'i');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS))   ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))  ? 'A' : 'a');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))  ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO))          ? 'S' : 's');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO))          ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK))                 ? 'B' : 'b');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_BACK))                 ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME))                 ? 'H' : 'h');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_HOME))                 ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT))               ? 'R' : 'r');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_RECENT))               ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK))                ? 'C' : 'c');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_CLOCK))                ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH))               ? 'S' : 's');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SEARCH))               ? '!' : ' ');
+        flagdbg.append("> disable2<");
+        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS))      ? 'Q' : 'q');
+        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS))      ? '!' : ' ');
+        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS))        ? 'I' : 'i');
+        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_SYSTEM_ICONS))        ? '!' : ' ');
+        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))  ? 'N' : 'n');
+        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_NOTIFICATION_SHADE))  ? '!' : ' ');
+        flagdbg.append('>');
+        Log.d(StatusBar.TAG, flagdbg.toString());
+
+        if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+            if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+                mShadeController.animateCollapsePanels();
+            }
+        }
+
+        if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
+            if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
+                // close recents if it's visible
+                mStatusBar.resetHandlerMsg(StatusBar.MSG_HIDE_RECENT_APPS);
+            }
+        }
+
+        if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
+            if (mStatusBar.areNotificationAlertsDisabled()) {
+                mHeadsUpManager.releaseAllImmediately();
+            }
+        }
+
+        if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
+            mStatusBar.updateQsExpansionEnabled();
+        }
+
+        if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+            mStatusBar.updateQsExpansionEnabled();
+            if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+                mShadeController.animateCollapsePanels();
+            }
+        }
+    }
+
+    /**
+     * Called for system navigation gestures. First action opens the panel, second opens
+     * settings. Down action closes the entire panel.
+     */
+    @Override
+    public void handleSystemKey(int key) {
+        if (StatusBar.SPEW) {
+            Log.d(StatusBar.TAG, "handleNavigationKey: " + key);
+        }
+        if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
+                || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
+            return;
+        }
+
+        // Panels are not available in setup
+        if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+        if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
+            mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
+            mNotificationPanelViewController.collapse(
+                    false /* delayed */, 1.0f /* speedUpFactor */);
+        } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
+            mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
+            if (mNotificationPanelViewController.isFullyCollapsed()) {
+                if (mVibrateOnOpening) {
+                    mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+                }
+                mNotificationPanelViewController.expand(true /* animate */);
+                mNotificationStackScrollLayoutController.setWillExpand(true);
+                mHeadsUpManager.unpinAll(true /* userUnpinned */);
+                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
+            } else if (!mNotificationPanelViewController.isInSettings()
+                    && !mNotificationPanelViewController.isExpanding()) {
+                mNotificationPanelViewController.flingSettings(0 /* velocity */,
+                        NotificationPanelView.FLING_EXPAND);
+                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
+            }
+        }
+
+    }
+
+    @Override
+    public void onCameraLaunchGestureDetected(int source) {
+        mStatusBar.setLastCameraLaunchSource(source);
+        if (mStatusBar.isGoingToSleep()) {
+            if (StatusBar.DEBUG_CAMERA_LIFT) {
+                Slog.d(StatusBar.TAG, "Finish going to sleep before launching camera");
+            }
+            mStatusBar.setLaunchCameraOnFinishedGoingToSleep(true);
+            return;
+        }
+        if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
+            if (StatusBar.DEBUG_CAMERA_LIFT) {
+                Slog.d(StatusBar.TAG, "Can't launch camera right now");
+            }
+            return;
+        }
+        if (!mStatusBar.isDeviceInteractive()) {
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+                    "com.android.systemui:CAMERA_GESTURE");
+        }
+        vibrateForCameraGesture();
+
+        if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+            Log.v(StatusBar.TAG, "Camera launch");
+            mKeyguardUpdateMonitor.onCameraLaunched();
+        }
+
+        if (!mStatusBarKeyguardViewManager.isShowing()) {
+            final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
+            mStatusBar.startActivityDismissingKeyguard(cameraIntent,
+                    false /* onlyProvisioned */, true /* dismissShade */,
+                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+                    null /* animationController */);
+        } else {
+            if (!mStatusBar.isDeviceInteractive()) {
+                // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+                // comes on.
+                mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+            }
+            if (isWakingUpOrAwake()) {
+                if (StatusBar.DEBUG_CAMERA_LIFT) {
+                    Slog.d(StatusBar.TAG, "Launching camera");
+                }
+                if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+                    mStatusBarKeyguardViewManager.reset(true /* hide */);
+                }
+                mNotificationPanelViewController.launchCamera(
+                        mStatusBar.isDeviceInteractive() /* animate */, source);
+                mStatusBar.updateScrimController();
+            } else {
+                // We need to defer the camera launch until the screen comes on, since otherwise
+                // we will dismiss us too early since we are waiting on an activity to be drawn and
+                // incorrectly get notified because of the screen on event (which resumes and pauses
+                // some activities)
+                if (StatusBar.DEBUG_CAMERA_LIFT) {
+                    Slog.d(StatusBar.TAG, "Deferring until screen turns on");
+                }
+                mStatusBar.setLaunchCameraOnFinishedWaking(true);
+            }
+        }
+    }
+
+    @Override
+    public void onEmergencyActionLaunchGestureDetected() {
+        Intent emergencyIntent = mStatusBar.getEmergencyActionIntent();
+
+        if (emergencyIntent == null) {
+            Log.wtf(StatusBar.TAG, "Couldn't find an app to process the emergency intent.");
+            return;
+        }
+
+        if (isGoingToSleep()) {
+            mStatusBar.setLaunchEmergencyActionOnFinishedGoingToSleep(true);
+            return;
+        }
+
+        if (!mStatusBar.isDeviceInteractive()) {
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                    PowerManager.WAKE_REASON_GESTURE,
+                    "com.android.systemui:EMERGENCY_GESTURE");
+        }
+        // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
+        // app-side haptic experimentation.
+
+        if (!mStatusBarKeyguardViewManager.isShowing()) {
+            mStatusBar.startActivityDismissingKeyguard(emergencyIntent,
+                    false /* onlyProvisioned */, true /* dismissShade */,
+                    true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+                    null /* animationController */);
+            return;
+        }
+
+        if (!mStatusBar.isDeviceInteractive()) {
+            // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+            // comes on.
+            mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+        }
+
+        if (isWakingUpOrAwake()) {
+            if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+                mStatusBarKeyguardViewManager.reset(true /* hide */);
+            }
+            mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+            return;
+        }
+        // We need to defer the emergency action launch until the screen comes on, since otherwise
+        // we will dismiss us too early since we are waiting on an activity to be drawn and
+        // incorrectly get notified because of the screen on event (which resumes and pauses
+        // some activities)
+        mStatusBar.setLaunchEmergencyActionOnFinishedWaking(true);
+    }
+
+    @Override
+    public void onRecentsAnimationStateChanged(boolean running) {
+        mStatusBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
+    }
+
+
+    @Override
+    public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+            AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+            @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        boolean barModeChanged = mStatusBar.setAppearance(appearance);
+
+        mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
+                mStatusBar.getBarMode(), navbarColorManagedByIme);
+
+        mStatusBar.updateBubblesVisibility();
+        mStatusBarStateController.setSystemBarAttributes(
+                appearance, behavior, requestedVisibilities, packageName);
+    }
+
+    @Override
+    public void showTransient(int displayId, @InternalInsetsType int[] types) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        if (!containsType(types, ITYPE_STATUS_BAR)) {
+            return;
+        }
+        mStatusBar.showTransientUnchecked();
+    }
+
+    @Override
+    public void toggleKeyboardShortcutsMenu(int deviceId) {
+        int msg = StatusBar.MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
+        mStatusBar.getHandler().removeMessages(msg);
+        mStatusBar.getHandler().obtainMessage(msg, deviceId, 0).sendToTarget();
+    }
+
+    @Override
+    public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
+        mStatusBar.setTopHidesStatusBar(topAppHidesStatusBar);
+        if (!topAppHidesStatusBar && mStatusBar.getWereIconsJustHidden()) {
+            // Immediately update the icon hidden state, since that should only apply if we're
+            // staying fullscreen.
+            mStatusBar.setWereIconsJustHidden(false);
+            mCommandQueue.recomputeDisableFlags(mDisplayId, true);
+        }
+        mStatusBar.updateHideIconsForBouncer(true /* animate */);
+    }
+
+    @Override
+    public void setWindowState(
+            int displayId, @StatusBarManager.WindowType int window,
+            @StatusBarManager.WindowVisibleState int state) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        boolean showing = state == WINDOW_STATE_SHOWING;
+        if (mNotificationShadeWindowView != null
+                && window == StatusBarManager.WINDOW_STATUS_BAR
+                && !mStatusBar.isSameStatusBarState(state)) {
+            mStatusBar.setWindowState(state);
+            if (StatusBar.DEBUG_WINDOW_STATE) {
+                Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state));
+            }
+            if (mStatusBar.getStatusBarView() != null) {
+                if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+                    mStatusBar.getStatusBarView().collapsePanel(
+                            false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */);
+                }
+
+                mStatusBar.updateHideIconsForBouncer(false /* animate */);
+            }
+        }
+
+        mStatusBar.updateBubblesVisibility();
+    }
+
+    @Override
+    public void showAssistDisclosure() {
+        mAssistManager.showDisclosure();
+    }
+
+    @Override
+    public void showPinningEnterExitToast(boolean entering) {
+        if (mStatusBar.getNavigationBarView() != null) {
+            mStatusBar.getNavigationBarView().showPinningEnterExitToast(entering);
+        }
+    }
+
+    @Override
+    public void showPinningEscapeToast() {
+        if (mStatusBar.getNavigationBarView() != null) {
+            mStatusBar.getNavigationBarView().showPinningEscapeToast();
+        }
+    }
+
+    @Override
+    public void showScreenPinningRequest(int taskId) {
+        if (mKeyguardStateController.isShowing()) {
+            // Don't allow apps to trigger this from keyguard.
+            return;
+        }
+        // Show screen pinning request, since this comes from an app, show 'no thanks', button.
+        mStatusBar.showScreenPinningRequest(taskId, true);
+    }
+
+    @Override
+    public void showWirelessChargingAnimation(int batteryLevel) {
+        mStatusBar.showWirelessChargingAnimation(batteryLevel);
+    }
+
+    @Override
+    public void startAssist(Bundle args) {
+        mAssistManager.startAssist(args);
+    }
+
+    @Override
+    public void suppressAmbientDisplay(boolean suppressed) {
+        mDozeServiceHost.setDozeSuppressed(suppressed);
+    }
+
+    @Override
+    public void togglePanel() {
+        if (mStatusBar.isPanelExpanded()) {
+            mShadeController.animateCollapsePanels();
+        } else {
+            animateExpandNotificationsPanel();
+        }
+    }
+
+    @Override
+    public void toggleSplitScreen() {
+        mStatusBar.toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
+    }
+
+    private boolean isGoingToSleep() {
+        return mWakefulnessLifecycle.getWakefulness()
+                == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
+    }
+
+    private boolean isWakingUpOrAwake() {
+        return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
+                || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
+    }
+
+    private void vibrateForCameraGesture() {
+        // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+        mVibratorOptional.ifPresent(
+                v -> v.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES));
+    }
+
+    private static VibrationEffect getCameraGestureVibrationEffect(
+            Optional<Vibrator> vibratorOptional, Resources resources) {
+        if (vibratorOptional.isPresent() && vibratorOptional.get().areAllPrimitivesSupported(
+                VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
+                VibrationEffect.Composition.PRIMITIVE_CLICK)) {
+            return VibrationEffect.startComposition()
+                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
+                    .compose();
+        }
+        if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) {
+            return VibrationEffect.createWaveform(
+                    StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
+                    StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
+                    /* repeat= */ -1);
+        }
+
+        int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
+        long[] timings = new long[pattern.length];
+        for (int i = 0; i < pattern.length; i++) {
+            timings[i] = pattern[i];
+        }
+        return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
new file mode 100644
index 0000000..e642b2e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarDemoMode implements DemoMode {
+    private final StatusBar mStatusBar;
+    private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private final NotificationShadeWindowViewController mNotificationShadeWindowViewController;
+    private final NavigationBarController mNavigationBarController;
+    private final int mDisplayId;
+
+    @Inject
+    StatusBarDemoMode(
+            StatusBar statusBar,
+            NotificationShadeWindowController notificationShadeWindowController,
+            NotificationShadeWindowViewController notificationShadeWindowViewController,
+            NavigationBarController navigationBarController,
+            @DisplayId int displayId) {
+        mStatusBar = statusBar;
+        mNotificationShadeWindowController = notificationShadeWindowController;
+        mNotificationShadeWindowViewController = notificationShadeWindowViewController;
+        mNavigationBarController = navigationBarController;
+        mDisplayId = displayId;
+    }
+
+    @Override
+    public List<String> demoCommands() {
+        List<String> s = new ArrayList<>();
+        s.add(DemoMode.COMMAND_BARS);
+        s.add(DemoMode.COMMAND_CLOCK);
+        s.add(DemoMode.COMMAND_OPERATOR);
+        return s;
+    }
+
+    @Override
+    public void onDemoModeStarted() {
+        // Must send this message to any view that we delegate to via dispatchDemoCommandToView
+        dispatchDemoModeStartedToView(R.id.clock);
+        dispatchDemoModeStartedToView(R.id.operator_name);
+    }
+
+    @Override
+    public void onDemoModeFinished() {
+        dispatchDemoModeFinishedToView(R.id.clock);
+        dispatchDemoModeFinishedToView(R.id.operator_name);
+        mStatusBar.checkBarModes();
+    }
+
+    @Override
+    public void dispatchDemoCommand(String command, @NonNull Bundle args) {
+        if (command.equals(COMMAND_CLOCK)) {
+            dispatchDemoCommandToView(command, args, R.id.clock);
+        }
+        if (command.equals(COMMAND_BARS)) {
+            String mode = args.getString("mode");
+            int barMode = "opaque".equals(mode) ? MODE_OPAQUE :
+                    "translucent".equals(mode) ? MODE_TRANSLUCENT :
+                            "semi-transparent".equals(mode) ? MODE_SEMI_TRANSPARENT :
+                                    "transparent".equals(mode) ? MODE_TRANSPARENT :
+                                            "warning".equals(mode) ? MODE_WARNING :
+                                                    -1;
+            if (barMode != -1) {
+                boolean animate = true;
+                if (mNotificationShadeWindowController != null
+                        && mNotificationShadeWindowViewController.getBarTransitions() != null) {
+                    mNotificationShadeWindowViewController.getBarTransitions().transitionTo(
+                            barMode, animate);
+                }
+                mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
+            }
+        }
+        if (command.equals(COMMAND_OPERATOR)) {
+            dispatchDemoCommandToView(command, args, R.id.operator_name);
+        }
+    }
+
+    private void dispatchDemoModeStartedToView(int id) {
+        View statusBarView = mStatusBar.getStatusBarView();
+        if (statusBarView == null) return;
+        View v = statusBarView.findViewById(id);
+        if (v instanceof DemoModeCommandReceiver) {
+            ((DemoModeCommandReceiver) v).onDemoModeStarted();
+        }
+    }
+
+    //TODO: these should have controllers, and this method should be removed
+    private void dispatchDemoCommandToView(String command, Bundle args, int id) {
+        View statusBarView = mStatusBar.getStatusBarView();
+        if (statusBarView == null) return;
+        View v = statusBarView.findViewById(id);
+        if (v instanceof DemoModeCommandReceiver) {
+            ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args);
+        }
+    }
+
+    private void dispatchDemoModeFinishedToView(int id) {
+        View statusBarView = mStatusBar.getStatusBarView();
+        if (statusBarView == null) return;
+        View v = statusBarView.findViewById(id);
+        if (v instanceof DemoModeCommandReceiver) {
+            ((DemoModeCommandReceiver) v).onDemoModeFinished();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
new file mode 100644
index 0000000..ca877af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+
+import javax.inject.Inject;
+
+/** Ties the {@link StatusBar} to {@link com.android.systemui.statusbar.policy.HeadsUpManager}. */
+@StatusBarComponent.StatusBarScope
+public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener {
+    private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private final StatusBarWindowController mStatusBarWindowController;
+    private final NotificationPanelViewController mNotificationPanelViewController;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final HeadsUpManagerPhone mHeadsUpManager;
+    private final StatusBarStateController mStatusBarStateController;
+    private final NotificationRemoteInputManager mNotificationRemoteInputManager;
+    private final NotificationsController mNotificationsController;
+    private final DozeServiceHost mDozeServiceHost;
+    private final DozeScrimController mDozeScrimController;
+
+    @Inject
+    StatusBarHeadsUpChangeListener(
+            NotificationShadeWindowController notificationShadeWindowController,
+            StatusBarWindowController statusBarWindowController,
+            NotificationPanelViewController notificationPanelViewController,
+            KeyguardBypassController keyguardBypassController,
+            HeadsUpManagerPhone headsUpManager,
+            StatusBarStateController statusBarStateController,
+            NotificationRemoteInputManager notificationRemoteInputManager,
+            NotificationsController notificationsController,
+            DozeServiceHost dozeServiceHost,
+            DozeScrimController dozeScrimController) {
+
+        mNotificationShadeWindowController = notificationShadeWindowController;
+        mStatusBarWindowController = statusBarWindowController;
+        mNotificationPanelViewController = notificationPanelViewController;
+        mKeyguardBypassController = keyguardBypassController;
+        mHeadsUpManager = headsUpManager;
+        mStatusBarStateController = statusBarStateController;
+        mNotificationRemoteInputManager = notificationRemoteInputManager;
+        mNotificationsController = notificationsController;
+        mDozeServiceHost = dozeServiceHost;
+        mDozeScrimController = dozeScrimController;
+    }
+
+    @Override
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+        if (inPinnedMode) {
+            mNotificationShadeWindowController.setHeadsUpShowing(true);
+            mStatusBarWindowController.setForceStatusBarVisible(true);
+            if (mNotificationPanelViewController.isFullyCollapsed()) {
+                // We need to ensure that the touchable region is updated before the
+                //window will be
+                // resized, in order to not catch any touches. A layout will ensure that
+                // onComputeInternalInsets will be called and after that we can
+                //resize the layout. Let's
+                // make sure that the window stays small for one frame until the
+                //touchableRegion is set.
+                mNotificationPanelViewController.getView().requestLayout();
+                mNotificationShadeWindowController.setForceWindowCollapsed(true);
+                mNotificationPanelViewController.getView().post(() -> {
+                    mNotificationShadeWindowController.setForceWindowCollapsed(false);
+                });
+            }
+        } else {
+            boolean bypassKeyguard = mKeyguardBypassController.getBypassEnabled()
+                    && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+            if (!mNotificationPanelViewController.isFullyCollapsed()
+                    || mNotificationPanelViewController.isTracking()
+                    || bypassKeyguard) {
+                // We are currently tracking or is open and the shade doesn't need to
+                //be kept
+                // open artificially.
+                mNotificationShadeWindowController.setHeadsUpShowing(false);
+                if (bypassKeyguard) {
+                    mStatusBarWindowController.setForceStatusBarVisible(false);
+                }
+            } else {
+                // we need to keep the panel open artificially, let's wait until the
+                //animation
+                // is finished.
+                mHeadsUpManager.setHeadsUpGoingAway(true);
+                mNotificationPanelViewController.runAfterAnimationFinished(() -> {
+                    if (!mHeadsUpManager.hasPinnedHeadsUp()) {
+                        mNotificationShadeWindowController.setHeadsUpShowing(false);
+                        mHeadsUpManager.setHeadsUpGoingAway(false);
+                    }
+                    mNotificationRemoteInputManager.onPanelCollapsed();
+                });
+            }
+        }
+    }
+
+    @Override
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+        mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
+        if (mStatusBarStateController.isDozing() && isHeadsUp) {
+            entry.setPulseSuppressed(false);
+            mDozeServiceHost.fireNotificationPulse(entry);
+            if (mDozeServiceHost.isPulsing()) {
+                mDozeScrimController.cancelPendingPulseTimeout();
+            }
+        }
+        if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
+            // There are no longer any notifications to show.  We should end the
+            //pulse now.
+            mDozeScrimController.pulseOutNow();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index dbe4c1e..48fe774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -37,9 +37,9 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 1717b82..dba3b24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -52,10 +52,10 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationClickNotifier;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -71,6 +71,7 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -402,6 +403,53 @@
         mIsCollapsingToShowActivityOverLockscreen = false;
     }
 
+    /**
+     * Called when a notification is dropped on proper target window.
+     * Intent that is included in this entry notification,
+     * will be sent by {@link ExpandableNotificationRowDragController}
+     *
+     * @param entry notification entry that is dropped.
+     */
+    @Override
+    public void onDragSuccess(NotificationEntry entry) {
+        // this method is not responsible for intent sending.
+        // will focus follow operation only after drag-and-drop that notification.
+        NotificationVisibility.NotificationLocation location =
+                NotificationLogger.getNotificationLocation(entry);
+        final NotificationVisibility nv = NotificationVisibility.obtain(entry.getKey(),
+                entry.getRanking().getRank(), getVisibleNotificationsCount(), true, location);
+
+        // retrieve the group summary to remove with this entry before we tell NMS the
+        // notification was clicked to avoid a race condition
+        final boolean shouldAutoCancel = shouldAutoCancel(entry.getSbn());
+        final NotificationEntry summaryToRemove = shouldAutoCancel
+                ? mOnUserInteractionCallback.getGroupSummaryToDismiss(entry) : null;
+
+        String notificationKey = entry.getKey();
+        // inform NMS that the notification was clicked
+        mClickNotifier.onNotificationClick(notificationKey, nv);
+
+        if (shouldAutoCancel || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
+                notificationKey)) {
+            // Immediately remove notification from visually showing.
+            // We have to post the removal to the UI thread for synchronization.
+            mMainThreadHandler.post(() -> {
+                final Runnable removeNotification = () ->
+                        mOnUserInteractionCallback.onDismiss(
+                                entry, REASON_CLICK, summaryToRemove);
+                if (mPresenter.isCollapsing()) {
+                    // To avoid lags we're only performing the remove
+                    // after the shade is collapsed
+                    mShadeController.addPostCollapseAction(removeNotification);
+                } else {
+                    removeNotification.run();
+                }
+            });
+        }
+
+        mIsCollapsingToShowActivityOverLockscreen = false;
+    }
+
     private void expandBubbleStackOnMainThread(NotificationEntry entry) {
         if (!mBubblesManagerOptional.isPresent()) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index fe52281..7136432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -25,7 +25,7 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index a5b868b..6b52dca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -149,14 +149,18 @@
         lightRevealAnimationPlaying = false
         aodUiAnimationPlaying = false
 
-        // Make sure the status bar is in the correct keyguard state, forcing it if necessary. This
-        // is required if the screen off animation is cancelled, since it might be incorrectly left
-        // in the KEYGUARD or SHADE states depending on when it was cancelled and whether 'lock
-        // instantly' is enabled. We need to force it so that the state is set even if we're going
-        // from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have changed parts of the UI
-        // (such as showing AOD in the shade) without actually changing the StatusBarState. This
-        // ensures that the UI definitely reflects the desired state.
-        statusBar.updateIsKeyguard(true /* force */)
+        // If we can't control the screen off animation, we shouldn't mess with the StatusBar's
+        // keyguard state unnecessarily.
+        if (dozeParameters.get().canControlUnlockedScreenOff()) {
+            // Make sure the status bar is in the correct keyguard state, forcing it if necessary.
+            // This is required if the screen off animation is cancelled, since it might be
+            // incorrectly left in the KEYGUARD or SHADE states depending on when it was cancelled
+            // and whether 'lock instantly' is enabled. We need to force it so that the state is set
+            // even if we're going from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have
+            // changed parts of the UI (such as showing AOD in the shade) without actually changing
+            // the StatusBarState. This ensures that the UI definitely reflects the desired state.
+            statusBar.updateIsKeyguard(true /* force */)
+        }
     }
 
     override fun onStartedGoingToSleep() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index 4fab226..d408c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -24,6 +24,9 @@
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
 import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
+import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks;
+import com.android.systemui.statusbar.phone.StatusBarDemoMode;
+import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 
 import java.lang.annotation.Documented;
@@ -89,6 +92,24 @@
     AuthRippleController getAuthRippleController();
 
     /**
+     * Creates a StatusBarDemoMode.
+     */
+    @StatusBarScope
+    StatusBarDemoMode getStatusBarDemoMode();
+
+    /**
+     * Creates a StatusBarHeadsUpChangeListener.
+     */
+    @StatusBarScope
+    StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
+
+    /**
+     * Creates a StatusBarCommandQueueCallbacks.
+     */
+    @StatusBarScope
+    StatusBarCommandQueueCallbacks getStatusBarCommandQueueCallbacks();
+
+    /**
      * Creates a SplitShadeHeaderController.
      */
     @StatusBarScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 5e8eecb..eabb2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -18,18 +18,16 @@
 
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
 
+import android.app.WallpaperManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.util.DisplayMetrics;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.InitController;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
@@ -37,7 +35,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -48,9 +46,7 @@
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.settings.brightness.BrightnessSlider;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -62,8 +58,6 @@
 import com.android.systemui.statusbar.PulseExpansionHandler;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -81,7 +75,6 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LightsOutNotifController;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -94,7 +87,6 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
@@ -104,12 +96,13 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
@@ -140,7 +133,6 @@
             LightBarController lightBarController,
             AutoHideController autoHideController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            StatusBarSignalPolicy signalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
@@ -151,7 +143,6 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
-            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -170,19 +161,16 @@
             ScreenLifecycle screenLifecycle,
             WakefulnessLifecycle wakefulnessLifecycle,
             SysuiStatusBarStateController statusBarStateController,
-            VibratorHelper vibratorHelper,
             Optional<BubblesManager> bubblesManagerOptional,
             Optional<Bubbles> bubblesOptional,
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AccessibilityFloatingMenuController accessibilityFloatingMenuController,
             Lazy<AssistManager> assistManagerLazy,
             ConfigurationController configurationController,
             NotificationShadeWindowController notificationShadeWindowController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
-            @Nullable KeyguardLiftController keyguardLiftController,
             Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
@@ -211,11 +199,9 @@
             KeyguardIndicationController keyguardIndicationController,
             DemoModeController demoModeController,
             Lazy<NotificationShadeDepthController> notificationShadeDepthController,
-            DismissCallbackRegistry dismissCallbackRegistry,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             NotificationIconAreaController notificationIconAreaController,
             BrightnessSlider.Factory brightnessSliderFactory,
-            WiredChargingRippleController chargingRippleAnimationController,
             UnfoldTransitionConfig unfoldTransitionConfig,
             Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
             OngoingCallController ongoingCallController,
@@ -225,15 +211,16 @@
             LockscreenShadeTransitionController transitionController,
             FeatureFlags featureFlags,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+            WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         return new StatusBar(
                 context,
                 notificationsController,
                 lightBarController,
                 autoHideController,
                 keyguardUpdateMonitor,
-                signalPolicy,
                 pulseExpansionHandler,
                 notificationWakeUpCoordinator,
                 keyguardBypassController,
@@ -244,7 +231,6 @@
                 falsingManager,
                 falsingCollector,
                 broadcastDispatcher,
-                remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
                 notificationLogger,
                 notificationInterruptStateProvider,
@@ -263,19 +249,16 @@
                 screenLifecycle,
                 wakefulnessLifecycle,
                 statusBarStateController,
-                vibratorHelper,
                 bubblesManagerOptional,
                 bubblesOptional,
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
-                accessibilityFloatingMenuController,
                 assistManagerLazy,
                 configurationController,
                 notificationShadeWindowController,
                 dozeParameters,
                 scrimController,
-                keyguardLiftController,
                 lockscreenWallpaperLazy,
                 biometricUnlockControllerLazy,
                 dozeServiceHost,
@@ -301,13 +284,11 @@
                 userInfoControllerImpl,
                 phoneStatusBarPolicy,
                 keyguardIndicationController,
-                dismissCallbackRegistry,
                 demoModeController,
                 notificationShadeDepthController,
                 statusBarTouchableRegionManager,
                 notificationIconAreaController,
                 brightnessSliderFactory,
-                chargingRippleAnimationController,
                 unfoldTransitionConfig,
                 unfoldLightRevealOverlayAnimation,
                 ongoingCallController,
@@ -317,7 +298,9 @@
                 transitionController,
                 featureFlags,
                 keyguardUnlockAnimationController,
+                wallpaperManager,
                 unlockedScreenOffAnimationController,
-                startingSurfaceOptional);
+                startingSurfaceOptional,
+                tunerService);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index d691dca..0e83eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -21,6 +21,7 @@
 
 import com.android.keyguard.LockIconView;
 import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.biometrics.AuthRippleView;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -73,6 +74,13 @@
     /** */
     @Provides
     @StatusBarComponent.StatusBarScope
+    static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) {
+        return view.findViewById(R.id.batteryRemainingIcon);
+    }
+
+    /** */
+    @Provides
+    @StatusBarComponent.StatusBarScope
     public static TapAgainView getTapAgainView(NotificationPanelView npv) {
         return npv.getTapAgainView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 16fa5da..62ba56a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -24,7 +24,6 @@
 import android.content.Intent
 import android.util.Log
 import android.view.View
-import android.widget.Chronometer
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.R
@@ -32,7 +31,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -130,7 +129,6 @@
         }
     }
 
-
     /**
      * Called when the chip's visibility may have changed.
      *
@@ -218,9 +216,17 @@
         isCallAppVisible = isProcessVisibleToUser(
                 iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null))
 
+        if (uidObserver != null) {
+            iActivityManager.unregisterUidObserver(uidObserver)
+        }
+
         uidObserver = object : IUidObserver.Stub() {
             override fun onUidStateChanged(
-                    uid: Int, procState: Int, procStateSeq: Long, capability: Int) {
+                uid: Int,
+                procState: Int,
+                procStateSeq: Long,
+                capability: Int
+            ) {
                 if (uid == currentCallNotificationInfo.uid) {
                     val oldIsCallAppVisible = isCallAppVisible
                     isCallAppVisible = isProcessVisibleToUser(procState)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 4ca1f60..d80fa12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
-import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.SimpleClock;
@@ -286,7 +285,6 @@
         private final Context mContext;
         private final @Nullable WifiManager mWifiManager;
         private final ConnectivityManager mConnectivityManager;
-        private final NetworkScoreManager mNetworkScoreManager;
         private final Handler mMainHandler;
         private final Handler mWorkerHandler;
         private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@@ -301,14 +299,12 @@
                 Context context,
                 @Nullable WifiManager wifiManager,
                 ConnectivityManager connectivityManager,
-                NetworkScoreManager networkScoreManager,
                 @Main Handler mainHandler,
                 @Background Handler workerHandler
         ) {
             mContext = context;
             mWifiManager = wifiManager;
             mConnectivityManager = connectivityManager;
-            mNetworkScoreManager = networkScoreManager;
             mMainHandler = mainHandler;
             mWorkerHandler = workerHandler;
         }
@@ -332,7 +328,6 @@
                     mContext,
                     mWifiManager,
                     mConnectivityManager,
-                    mNetworkScoreManager,
                     mMainHandler,
                     mWorkerHandler,
                     mClock,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
new file mode 100644
index 0000000..41cacf5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
+
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
+import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Handles reading and writing of rotation lock settings per device state, as well as setting
+ * the rotation lock when device state changes.
+ **/
+@SysUISingleton
+public final class DeviceStateRotationLockSettingController implements Listenable,
+        RotationLockController.RotationLockControllerCallback {
+
+    private static final String TAG = "DSRotateLockSettingCon";
+
+    private static final String SEPARATOR_REGEX = ":";
+
+    private final SecureSettings mSecureSettings;
+    private final RotationPolicyWrapper mRotationPolicyWrapper;
+    private final DeviceStateManager mDeviceStateManager;
+    private final Executor mMainExecutor;
+    private final String[] mDeviceStateRotationLockDefaults;
+
+    private SparseIntArray mDeviceStateRotationLockSettings;
+    // TODO(b/183001527): Add API to query current device state and initialize this.
+    private int mDeviceState = -1;
+    @Nullable
+    private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+
+    @Inject
+    public DeviceStateRotationLockSettingController(
+            SecureSettings secureSettings,
+            RotationPolicyWrapper rotationPolicyWrapper,
+            DeviceStateManager deviceStateManager,
+            @Main Executor executor,
+            @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+    ) {
+        mSecureSettings = secureSettings;
+        mRotationPolicyWrapper = rotationPolicyWrapper;
+        mDeviceStateManager = deviceStateManager;
+        mMainExecutor = executor;
+        mDeviceStateRotationLockDefaults = deviceStateRotationLockDefaults;
+    }
+
+    /**
+     * Loads the settings from storage.
+     */
+    public void initialize() {
+        String serializedSetting =
+                mSecureSettings.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                        UserHandle.USER_CURRENT);
+        if (TextUtils.isEmpty(serializedSetting)) {
+            // No settings saved, we should load the defaults and persist them.
+            fallbackOnDefaults();
+            return;
+        }
+        String[] values = serializedSetting.split(SEPARATOR_REGEX);
+        if (values.length % 2 != 0) {
+            // Each entry should be a key/value pair, so this is corrupt.
+            Log.wtf(TAG, "Can't deserialize saved settings, falling back on defaults");
+            fallbackOnDefaults();
+            return;
+        }
+        mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+        int key;
+        int value;
+
+        for (int i = 0; i < values.length - 1; ) {
+            try {
+                key = Integer.parseInt(values[i++]);
+                value = Integer.parseInt(values[i++]);
+                mDeviceStateRotationLockSettings.put(key, value);
+            } catch (NumberFormatException e) {
+                Log.wtf(TAG, "Error deserializing one of the saved settings", e);
+                fallbackOnDefaults();
+                return;
+            }
+        }
+    }
+
+    private void fallbackOnDefaults() {
+        loadDefaults();
+        persistSettings();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            // Note that this is called once with the initial state of the device, even if there
+            // is no user action.
+            mDeviceStateCallback = this::updateDeviceState;
+            mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
+        } else {
+            if (mDeviceStateCallback != null) {
+                mDeviceStateManager.unregisterCallback(mDeviceStateCallback);
+            }
+        }
+    }
+
+    @Override
+    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+        if (mDeviceState == -1) {
+            Log.wtf(TAG, "Device state was not initialized.");
+            return;
+        }
+
+        if (rotationLocked == isRotationLockedForCurrentState()) {
+            Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
+            return;
+        }
+
+        saveNewRotationLockSetting(rotationLocked);
+    }
+
+    private void saveNewRotationLockSetting(boolean isRotationLocked) {
+        Log.v(TAG, "saveNewRotationLockSetting [state=" + mDeviceState + "] [isRotationLocked="
+                + isRotationLocked + "]");
+
+        mDeviceStateRotationLockSettings.put(mDeviceState,
+                isRotationLocked
+                        ? DEVICE_STATE_ROTATION_LOCK_LOCKED
+                        : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+        persistSettings();
+    }
+
+    private boolean isRotationLockedForCurrentState() {
+        return mDeviceStateRotationLockSettings.get(mDeviceState,
+                DEVICE_STATE_ROTATION_LOCK_IGNORED) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+    }
+
+    private void updateDeviceState(int state) {
+        Log.v(TAG, "updateDeviceState [state=" + state + "]");
+        if (mDeviceState == state) {
+            return;
+        }
+
+        int rotationLockSetting =
+                mDeviceStateRotationLockSettings.get(state, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+        if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+            // We won't handle this device state. The same rotation lock setting as before should
+            // apply and any changes to the rotation lock setting will be written for the previous
+            // valid device state.
+            Log.v(TAG, "Ignoring new device state: " + state);
+            return;
+        }
+
+        // Accept the new state
+        mDeviceState = state;
+
+        // Update the rotation lock setting if needed for this new device state
+        boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+        if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
+            mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
+        }
+    }
+
+    private void persistSettings() {
+        if (mDeviceStateRotationLockSettings.size() == 0) {
+            mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                    /* value= */"", UserHandle.USER_CURRENT);
+            return;
+        }
+
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(mDeviceStateRotationLockSettings.keyAt(0))
+                .append(SEPARATOR_REGEX)
+                .append(mDeviceStateRotationLockSettings.valueAt(0));
+
+        for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+            stringBuilder
+                    .append(SEPARATOR_REGEX)
+                    .append(mDeviceStateRotationLockSettings.keyAt(i))
+                    .append(SEPARATOR_REGEX)
+                    .append(mDeviceStateRotationLockSettings.valueAt(i));
+        }
+        mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                stringBuilder.toString(), UserHandle.USER_CURRENT);
+    }
+
+    private void loadDefaults() {
+        if (mDeviceStateRotationLockDefaults.length == 0) {
+            Log.w(TAG, "Empty default settings");
+            mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */0);
+            return;
+        }
+        mDeviceStateRotationLockSettings =
+                new SparseIntArray(mDeviceStateRotationLockDefaults.length);
+        for (String serializedDefault : mDeviceStateRotationLockDefaults) {
+            String[] entry = serializedDefault.split(SEPARATOR_REGEX);
+            try {
+                int key = Integer.parseInt(entry[0]);
+                int value = Integer.parseInt(entry[1]);
+                mDeviceStateRotationLockSettings.put(key, value);
+            } catch (NumberFormatException e) {
+                Log.wtf(TAG, "Error deserializing default settings", e);
+            }
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 43781f3..3490e15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -57,7 +57,7 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.net.SignalStrengthUtil;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 52c37a9..d6ac6d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -71,10 +71,10 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
 import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
 import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 53d68d0..67f5364 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -16,36 +16,54 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.Context;
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
 
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /** Platform implementation of the rotation lock controller. **/
 @SysUISingleton
 public final class RotationLockControllerImpl implements RotationLockController {
-    private final Context mContext;
     private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
-            new CopyOnWriteArrayList<RotationLockControllerCallback>();
+            new CopyOnWriteArrayList<>();
 
-    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
-            new RotationPolicy.RotationPolicyListener() {
+    private final RotationPolicyListener mRotationPolicyListener =
+            new RotationPolicyListener() {
         @Override
         public void onChange() {
             notifyChanged();
         }
     };
 
+    private final RotationPolicyWrapper mRotationPolicy;
+    private final DeviceStateRotationLockSettingController
+            mDeviceStateRotationLockSettingController;
+    private final boolean mIsPerDeviceStateRotationLockEnabled;
+
     @Inject
-    public RotationLockControllerImpl(Context context) {
-        mContext = context;
+    public RotationLockControllerImpl(
+            RotationPolicyWrapper rotationPolicyWrapper,
+            DeviceStateRotationLockSettingController deviceStateRotationLockSettingController,
+            @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+    ) {
+        mRotationPolicy = rotationPolicyWrapper;
+        mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
+        mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
+        if (mIsPerDeviceStateRotationLockEnabled) {
+            deviceStateRotationLockSettingController.initialize();
+            mCallbacks.add(mDeviceStateRotationLockSettingController);
+        }
+
         setListening(true);
     }
 
@@ -61,32 +79,35 @@
     }
 
     public int getRotationLockOrientation() {
-        return RotationPolicy.getRotationLockOrientation(mContext);
+        return mRotationPolicy.getRotationLockOrientation();
     }
 
     public boolean isRotationLocked() {
-        return RotationPolicy.isRotationLocked(mContext);
+        return mRotationPolicy.isRotationLocked();
     }
 
     public void setRotationLocked(boolean locked) {
-        RotationPolicy.setRotationLock(mContext, locked);
+        mRotationPolicy.setRotationLock(locked);
     }
 
     public void setRotationLockedAtAngle(boolean locked, int rotation){
-        RotationPolicy.setRotationLockAtAngle(mContext, locked, rotation);
+        mRotationPolicy.setRotationLockAtAngle(locked, rotation);
     }
 
     public boolean isRotationLockAffordanceVisible() {
-        return RotationPolicy.isRotationLockToggleVisible(mContext);
+        return mRotationPolicy.isRotationLockToggleVisible();
     }
 
     @Override
     public void setListening(boolean listening) {
         if (listening) {
-            RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
+            mRotationPolicy.registerRotationPolicyListener(mRotationPolicyListener,
                     UserHandle.USER_ALL);
         } else {
-            RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+            mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener);
+        }
+        if (mIsPerDeviceStateRotationLockEnabled) {
+            mDeviceStateRotationLockSettingController.setListening(listening);
         }
     }
 
@@ -97,7 +118,7 @@
     }
 
     private void notifyChanged(RotationLockControllerCallback callback) {
-        callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
-                RotationPolicy.isRotationLockToggleVisible(mContext));
+        callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
+                mRotationPolicy.isRotationLockToggleVisible());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 8f1a578..251ecc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -26,6 +26,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityTaskManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -114,6 +115,8 @@
     @VisibleForTesting
     final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
     private final KeyguardStateController mKeyguardStateController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+    private final DevicePolicyManager mDevicePolicyManager;
     protected final Handler mHandler;
     private final ActivityStarter mActivityStarter;
     private final BroadcastDispatcher mBroadcastDispatcher;
@@ -149,6 +152,8 @@
             UserManager userManager,
             UserTracker userTracker,
             KeyguardStateController keyguardStateController,
+            DeviceProvisionedController deviceProvisionedController,
+            DevicePolicyManager devicePolicyManager,
             @Main Handler handler,
             ActivityStarter activityStarter,
             BroadcastDispatcher broadcastDispatcher,
@@ -178,6 +183,8 @@
         mGuestIsResetting = new AtomicBoolean();
         mGuestCreationScheduled = new AtomicBoolean();
         mKeyguardStateController = keyguardStateController;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mDevicePolicyManager = devicePolicyManager;
         mHandler = handler;
         mActivityStarter = activityStarter;
         mUserManager = userManager;
@@ -336,8 +343,7 @@
                                 true /* isGuest */, false /* isCurrent */,
                                 false /* isAddUser */, false /* isRestricted */,
                                 isSwitchToGuestEnabled);
-                        // Don't call checkIfAddUserDisallowedByAdminOnly if
-                        // config_guestUserAutoCreated=true.
+                        checkIfAddUserDisallowedByAdminOnly(guestRecord);
                         records.add(guestRecord);
                     } else if (canCreateGuest) {
                         guestRecord = new UserRecord(null /* info */, null /* picture */,
@@ -733,10 +739,27 @@
     }
 
     /**
+     * Guarantee guest is present only if the device is provisioned. Otherwise, create a content
+     * observer to wait until the device is provisioned, then schedule the guest creation.
+     */
+    public void schedulePostBootGuestCreation() {
+        if (isDeviceAllowedToAddGuest()) {
+            guaranteeGuestPresent();
+        } else {
+            mDeviceProvisionedController.addCallback(mGuaranteeGuestPresentAfterProvisioned);
+        }
+    }
+
+    private boolean isDeviceAllowedToAddGuest() {
+        return mDeviceProvisionedController.isDeviceProvisioned()
+                && !mDevicePolicyManager.isDeviceManaged();
+    }
+
+    /**
      * If there is no guest on the device, schedule creation of a new guest user in the background.
      */
-    public void guaranteeGuestPresent() {
-        if (mUserManager.findCurrentGuestUser() == null) {
+    private void guaranteeGuestPresent() {
+        if (isDeviceAllowedToAddGuest() && mUserManager.findCurrentGuestUser() == null) {
             scheduleGuestCreation();
         }
     }
@@ -1056,6 +1079,21 @@
                 }
             };
 
+    private final DeviceProvisionedController.DeviceProvisionedListener
+            mGuaranteeGuestPresentAfterProvisioned =
+            new DeviceProvisionedController.DeviceProvisionedListener() {
+                @Override
+                public void onDeviceProvisionedChanged() {
+                    if (isDeviceAllowedToAddGuest()) {
+                        mBgExecutor.execute(
+                                () -> mDeviceProvisionedController.removeCallback(
+                                        mGuaranteeGuestPresentAfterProvisioned));
+                        guaranteeGuestPresent();
+                    }
+                }
+            };
+
+
     private final class ExitGuestDialog extends SystemUIDialog implements
             DialogInterface.OnClickListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index f8e3647..fc19564 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -36,7 +36,7 @@
 import com.android.settingslib.mobile.TelephonyIcons;
 import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index c224cf5..1eec639 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar.policy.dagger;
 
+import android.content.res.Resources;
 import android.os.UserManager;
 
+import com.android.internal.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
@@ -57,6 +59,8 @@
 
 import java.util.concurrent.Executor;
 
+import javax.inject.Named;
+
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
@@ -65,6 +69,9 @@
 /** Dagger Module for code in the statusbar.policy package. */
 @Module
 public interface StatusBarPolicyModule {
+
+    String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
+
     /** */
     @Binds
     BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);
@@ -154,4 +161,14 @@
         controller.init();
         return controller;
     }
+
+    /**
+     * Default values for per-device state rotation lock settings.
+     */
+    @Provides
+    @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS)
+    static String[] providesDeviceStateRotationLockDefaults(@Main Resources resources) {
+        return resources.getStringArray(
+                R.array.config_perDeviceStateRotationLockDefaults);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 9355244..cfd82f5 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -57,9 +57,9 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index df889f2..3525100 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -39,6 +39,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.recents.Recents;
@@ -81,6 +82,7 @@
  * overridden by the System UI implementation.
  */
 @Module(includes = {
+            PowerModule.class,
             QSModule.class
         },
         subcomponents = {
diff --git a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
index cdfa145..981bf01 100644
--- a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
@@ -18,12 +18,15 @@
 
 import com.android.systemui.util.RingerModeTracker;
 import com.android.systemui.util.RingerModeTrackerImpl;
+import com.android.systemui.util.wrapper.UtilWrapperModule;
 
 import dagger.Binds;
 import dagger.Module;
 
 /** Dagger Module for code in the util package. */
-@Module
+@Module(includes = {
+                UtilWrapperModule.class
+        })
 public interface UtilModule {
     /** */
     @Binds
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 19ed284..90e022a5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -281,17 +281,26 @@
 
         mLastPrimaryEvent = event;
 
-        if (event.getBelow() && mSecondaryThresholdSensor.isLoaded()) {
-            logDebug("Primary sensor is near. Checking secondary.");
+        if (mSecondarySafe && mSecondaryThresholdSensor.isLoaded()) {
+            logDebug("Primary sensor reported " + (event.getBelow() ? "near" : "far")
+                    + ". Checking secondary.");
             if (mCancelSecondaryRunnable == null) {
                 mSecondaryThresholdSensor.resume();
             }
-        } else {
-            if (!mSecondaryThresholdSensor.isLoaded()) {
-                logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
-            } else {
-                logDebug("Primary sensor event: " + event.getBelow() + ".");
+            return;
+        }
+
+
+        if (!mSecondaryThresholdSensor.isLoaded()) {  // No secondary
+            logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
+            onSensorEvent(event);
+        } else if (event.getBelow()) {  // Covered? Check secondary.
+            logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
+            if (mCancelSecondaryRunnable != null) {
+                mCancelSecondaryRunnable.run();
             }
+            mSecondaryThresholdSensor.resume();
+        } else {  // Uncovered. Report immediately.
             onSensorEvent(event);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
new file mode 100644
index 0000000..2a0cc7d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.wrapper
+
+import android.content.Context
+import com.android.internal.view.RotationPolicy
+import com.android.internal.view.RotationPolicy.RotationPolicyListener
+import javax.inject.Inject
+
+/**
+ * Testable wrapper interface around RotationPolicy {link com.android.internal.view.RotationPolicy}
+ */
+interface RotationPolicyWrapper {
+    fun setRotationLock(enabled: Boolean)
+    fun setRotationLockAtAngle(enabled: Boolean, rotation: Int)
+    fun getRotationLockOrientation(): Int
+    fun isRotationLockToggleVisible(): Boolean
+    fun isRotationLocked(): Boolean
+    fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int)
+    fun unregisterRotationPolicyListener(listener: RotationPolicyListener)
+}
+
+class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) :
+    RotationPolicyWrapper {
+
+    override fun setRotationLock(enabled: Boolean) {
+        RotationPolicy.setRotationLock(context, enabled)
+    }
+
+    override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int) {
+        RotationPolicy.setRotationLockAtAngle(context, enabled, rotation)
+    }
+
+    override fun getRotationLockOrientation(): Int =
+        RotationPolicy.getRotationLockOrientation(context)
+
+    override fun isRotationLockToggleVisible(): Boolean =
+        RotationPolicy.isRotationLockToggleVisible(context)
+
+    override fun isRotationLocked(): Boolean =
+        RotationPolicy.isRotationLocked(context)
+
+    override fun registerRotationPolicyListener(
+        listener: RotationPolicyListener,
+        userHandle: Int
+    ) {
+        RotationPolicy.registerRotationPolicyListener(context, listener, userHandle)
+    }
+
+    override fun unregisterRotationPolicyListener(listener: RotationPolicyListener) {
+        RotationPolicy.unregisterRotationPolicyListener(context, listener)
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
similarity index 66%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
index c7c2ad8..7e3aa27 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
@@ -14,6 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.systemui.util.wrapper
 
-parcelable InputConnectionCommand;
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+
+@Module
+abstract class UtilWrapperModule {
+
+    @Binds
+    @SysUISingleton
+    abstract fun bindRotationPolicyWrapper(impl: RotationPolicyWrapperImpl): RotationPolicyWrapper
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f317628..dbf115b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -2255,6 +2255,11 @@
 
         @Override
         public void onClick(View view) {
+            // If the ringer drawer isn't open, don't let anything in it be clicked.
+            if (!mIsRingerDrawerOpen) {
+                return;
+            }
+
             setRingerMode(mClickedRingerMode);
 
             mRingerDrawerIconAnimatingSelected = getDrawerIconViewForMode(mClickedRingerMode);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
index 1e1b459..77fd2e8 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
@@ -190,6 +190,15 @@
     }
 
     /**
+     * Sets the adapter again in the RecyclerView, updating the ViewHolders children's layout.
+     * This is needed when changing the state of the device (eg fold/unfold) so the ViewHolders are
+     * recreated.
+     */
+    void resetAdapter() {
+        setAdapter(mWalletCardCarouselAdapter);
+    }
+
+    /**
      * Returns true if the data set is changed.
      */
     boolean setData(List<WalletCardViewInfo> data, int selectedIndex, boolean hasLockStateChanged) {
@@ -376,8 +385,8 @@
             CardView cardView = viewHolder.mCardView;
             cardView.setRadius(mCornerRadiusPx);
             ViewGroup.LayoutParams layoutParams = cardView.getLayoutParams();
-            layoutParams.width = mCardWidthPx;
-            layoutParams.height = mCardHeightPx;
+            layoutParams.width = getCardWidthPx();
+            layoutParams.height = getCardHeightPx();
             view.setTag(viewHolder);
             return viewHolder;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 420f84a..9b2702f 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -99,17 +99,13 @@
         mCardCarousel.setExpectedViewWidth(getWidth());
     }
 
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        updateViewForOrientation(newConfig.orientation);
-    }
-
     private void updateViewForOrientation(@Configuration.Orientation int orientation) {
         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
             renderViewPortrait();
         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             renderViewLandscape();
         }
+        mCardCarousel.resetAdapter(); // necessary to update cards width
         ViewGroup.LayoutParams params = mCardCarouselContainer.getLayoutParams();
         if (params instanceof MarginLayoutParams) {
             ((MarginLayoutParams) params).topMargin =
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index a29a638..d3581a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -50,7 +50,6 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -61,11 +60,10 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
@@ -80,7 +78,6 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -118,7 +115,6 @@
     private final NotifPipeline mNotifPipeline;
     private final Executor mSysuiMainExecutor;
 
-    private ScrimView mBubbleScrim;
     private final Bubbles.SysuiProxy mSysuiProxy;
     // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
     private final List<NotifCallback> mCallbacks = new ArrayList<>();
@@ -193,12 +189,6 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE))
                 : statusBarService;
 
-        mBubbleScrim = new ScrimView(mContext);
-        mBubbleScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-        mBubbles.setBubbleScrim(mBubbleScrim, (executor, looper) -> {
-            mBubbleScrim.setExecutor(executor, looper);
-        });
-
         if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
             setupNotifPipeline();
         } else {
@@ -603,15 +593,6 @@
     }
 
     /**
-     * Returns the scrim drawn behind the bubble stack. This is managed by {@link ScrimController}
-     * since we want the scrim's appearance and behavior to be identical to that of the notification
-     * shade scrim.
-     */
-    public ScrimView getScrimForBubble() {
-        return mBubbleScrim;
-    }
-
-    /**
      * We intercept notification entries (including group summaries) dismissed by the user when
      * there is an active bubble associated with it. We do this so that developers can still
      * cancel it (and hence the bubbles associated with it).
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f2db4f1..db965db 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -242,6 +242,11 @@
     void initSplitScreen(SplitScreen splitScreen) {
         mSplitScreenKeyguardCallback = new KeyguardUpdateMonitorCallback() {
             @Override
+            public void onKeyguardVisibilityChanged(boolean showing) {
+                splitScreen.onKeyguardVisibilityChanged(showing);
+            }
+
+            @Override
             public void onKeyguardOccludedChanged(boolean occluded) {
                 splitScreen.onKeyguardOccludedChanged(occluded);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 7e733a9..7e3553a 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -55,6 +55,7 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -213,6 +214,13 @@
     }
 
     //
+    // Freeform (optional feature)
+    //
+
+    @BindsOptionalOf
+    abstract Optional<FreeformTaskListener> optionalFreeformTaskListener();
+
+    //
     // Hide display cutout
     //
 
@@ -328,9 +336,11 @@
     @WMSingleton
     @Provides
     static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
-            Context context, @ShellMainThread ShellExecutor mainExecutor,
+            DisplayController displayController, Context context,
+            @ShellMainThread ShellExecutor mainExecutor,
             @ShellAnimationThread ShellExecutor animExecutor) {
-        return new Transitions(organizer, pool, context, mainExecutor, animExecutor);
+        return new Transitions(organizer, pool, displayController, context, mainExecutor,
+                animExecutor);
     }
 
     //
@@ -451,6 +461,7 @@
             Optional<AppPairsController> appPairsOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             FullscreenTaskListener fullscreenTaskListener,
+            Optional<Optional<FreeformTaskListener>> freeformTaskListener,
             Transitions transitions,
             StartingWindowController startingWindow,
             @ShellMainThread ShellExecutor mainExecutor) {
@@ -463,6 +474,7 @@
                 appPairsOptional,
                 pipTouchHandlerOptional,
                 fullscreenTaskListener,
+                freeformTaskListener,
                 transitions,
                 startingWindow,
                 mainExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index be7813e..6397ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -36,6 +36,7 @@
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.Pip;
@@ -89,6 +90,18 @@
     }
 
     //
+    // Freeform
+    //
+
+    @WMSingleton
+    @Provides
+    static Optional<FreeformTaskListener> provideFreeformTaskListener(
+            Context context,
+            SyncTransactionQueue syncQueue) {
+        return Optional.ofNullable(FreeformTaskListener.create(context, syncQueue));
+    }
+
+    //
     // Split/multiwindow
     //
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 06b0bb2..ce65733 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -29,6 +28,7 @@
 import android.content.res.Resources;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
@@ -104,6 +104,8 @@
     private AnimatableClockView mLargeClockView;
     @Mock
     private FrameLayout mLargeClockFrame;
+    @Mock
+    private ViewGroup mSmartspaceContainer;
 
     private final View mFakeSmartspaceView = new View(mContext);
 
@@ -123,6 +125,8 @@
         when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
         when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
         when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
+        when(mView.findViewById(R.id.keyguard_smartspace_container))
+                .thenReturn(mSmartspaceContainer);
         when(mClockView.getContext()).thenReturn(getContext());
         when(mLargeClockView.getContext()).thenReturn(getContext());
 
@@ -210,7 +214,7 @@
 
     @Test
     public void testSmartspaceEnabledRemovesKeyguardStatusArea() {
-        when(mSmartspaceController.isEnabled()).thenReturn(true);
+        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
         mController.init();
 
@@ -219,7 +223,7 @@
 
     @Test
     public void testSmartspaceDisabledShowsKeyguardStatusArea() {
-        when(mSmartspaceController.isEnabled()).thenReturn(false);
+        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(false);
         mController.init();
 
         assertEquals(View.VISIBLE, mStatusArea.getVisibility());
@@ -227,17 +231,16 @@
 
     @Test
     public void testDetachRemovesSmartspaceView() {
-        when(mSmartspaceController.isEnabled()).thenReturn(true);
+        when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
         when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
         mController.init();
-        verify(mView).addView(eq(mFakeSmartspaceView), anyInt(), any());
 
         ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
         verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
 
         listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
-        verify(mView).removeView(mFakeSmartspaceView);
+        verify(mSmartspaceContainer).removeAllViews();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index bb71bed8..8e1e42a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.statusbar.policy.DevicePostureController
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -62,6 +63,8 @@
     private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
     @Mock
     private lateinit var mLockPatternView: LockPatternView
+    @Mock
+    private lateinit var mPostureController: DevicePostureController
 
     private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
 
@@ -78,7 +81,7 @@
         mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
         mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
                 mLatencyTracker, mFalsingCollector, mEmergencyButtonController,
-                mKeyguardMessageAreaControllerFactory)
+                mKeyguardMessageAreaControllerFactory, mPostureController)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index ec4dfba..d3557d4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -86,8 +86,8 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.telephony.TelephonyListenerManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 14f112b..cc35a8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -196,7 +196,7 @@
         return RemoteAnimationTarget(
                 0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
                 Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
-                taskInfo
+                taskInfo, false
         )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
new file mode 100644
index 0000000..903cbb5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery;
+
+import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.eq;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.os.Handler;
+import android.provider.Settings;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class BatteryMeterViewControllerTest extends SysuiTestCase {
+    @Mock
+    private BatteryMeterView mBatteryMeterView;
+
+    @Mock
+    private ConfigurationController mConfigurationController;
+    @Mock
+    private TunerService mTunerService;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private Handler mHandler;
+    @Mock
+    private ContentResolver mContentResolver;
+
+    private BatteryMeterViewController mController;
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mBatteryMeterView.getContext()).thenReturn(mContext);
+        when(mBatteryMeterView.getResources()).thenReturn(mContext.getResources());
+
+        mController = new BatteryMeterViewController(
+                mBatteryMeterView,
+                mConfigurationController,
+                mTunerService,
+                mBroadcastDispatcher,
+                mHandler,
+                mContentResolver
+        );
+    }
+
+    @Test
+    public void onViewAttached_callbacksRegistered() {
+        mController.onViewAttached();
+
+        verify(mConfigurationController).addCallback(any());
+        verify(mTunerService).addTunable(any(), any());
+        verify(mContentResolver).registerContentObserver(
+                eq(Settings.System.getUriFor(SHOW_BATTERY_PERCENT)), anyBoolean(), any(), anyInt()
+        );
+        verify(mContentResolver).registerContentObserver(
+                eq(Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)),
+                anyBoolean(),
+                any()
+        );
+    }
+
+    @Test
+    public void onViewDetached_callbacksUnregistered() {
+        // Set everything up first.
+        mController.onViewAttached();
+
+        mController.onViewDetached();
+
+        verify(mConfigurationController).removeCallback(any());
+        verify(mTunerService).removeTunable(any());
+        verify(mContentResolver).unregisterContentObserver(any());
+    }
+
+    @Test
+    public void ignoreTunerUpdates_afterOnViewAttached_callbackUnregistered() {
+        // Start out receiving tuner updates
+        mController.onViewAttached();
+
+        mController.ignoreTunerUpdates();
+
+        verify(mTunerService).removeTunable(any());
+    }
+
+    @Test
+    public void ignoreTunerUpdates_beforeOnViewAttached_callbackNeverRegistered() {
+        mController.ignoreTunerUpdates();
+
+        mController.onViewAttached();
+
+        verify(mTunerService, never()).addTunable(any(), any());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index 5cd7810..b6d1e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -23,7 +23,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -48,9 +47,9 @@
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -78,14 +77,16 @@
     @Mock private TextView mIndicatorView;
     @Mock private ImageView mIconView;
     @Mock private View mIconHolderView;
-    @Mock private AuthBiometricFaceView.IconController mIconController;
+    @Mock private AuthBiometricFaceView.IconController mFaceIconController;
+    @Mock private AuthBiometricFaceToFingerprintView.UdfpsIconController mUdfpsIconController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
         mFaceToFpView = new TestableView(mContext);
-        mFaceToFpView.mIconController = mIconController;
+        mFaceToFpView.mFaceIconController = mFaceIconController;
+        mFaceToFpView.mUdfpsIconController = mUdfpsIconController;
         mFaceToFpView.setCallback(mCallback);
 
         mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -99,20 +100,23 @@
     @Test
     public void testStateUpdated_whenDialogAnimatedIn() {
         mFaceToFpView.onDialogAnimatedIn();
-        verify(mFaceToFpView.mIconController)
+        verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
     }
 
     @Test
     public void testIconUpdatesState_whenDialogStateUpdated() {
         mFaceToFpView.onDialogAnimatedIn();
-        verify(mFaceToFpView.mIconController)
+        verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
-        verify(mFaceToFpView.mIconController).updateState(
+        verify(mFaceToFpView.mFaceIconController).updateState(
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
     }
@@ -120,21 +124,20 @@
     @Test
     public void testStateUpdated_whenSwitchToFingerprint() {
         mFaceToFpView.onDialogAnimatedIn();
-        verify(mFaceToFpView.mIconController)
+        verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
 
         mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
+
+        verify(mFaceToFpView.mFaceIconController).deactivate();
+        verify(mFaceToFpView.mUdfpsIconController).updateState(
+                eq(AuthBiometricFaceToFingerprintView.STATE_IDLE));
+        verify(mConfirmButton).setVisibility(eq(View.GONE));
+
         mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
 
-        InOrder order = inOrder(mFaceToFpView.mIconController);
-        order.verify(mFaceToFpView.mIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
-        order.verify(mFaceToFpView.mIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
+        verify(mFaceToFpView.mUdfpsIconController).updateState(
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-
-        verify(mConfirmButton).setVisibility(eq(View.GONE));
     }
 
     @Test
@@ -163,6 +166,7 @@
     }
 
     @Test
+    @Ignore("flaky, b/189031816")
     public void testModeUpdated_onSoftError_whenSwitchToFingerprint() {
         mFaceToFpView.onDialogAnimatedIn();
         mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
@@ -172,10 +176,14 @@
                 eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
         verify(mCallback).onAction(
                 eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
-        assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+        // First we enter the error state, since we need to show the error animation/text. The
+        // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+        assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
     }
 
     @Test
+    @Ignore("flaky, b/189031816")
     public void testModeUpdated_onHardError_whenSwitchToFingerprint() {
         mFaceToFpView.onDialogAnimatedIn();
         mFaceToFpView.onError(TYPE_FACE, "oh no!");
@@ -185,13 +193,16 @@
                 eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
         verify(mCallback).onAction(
                 eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
-        assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+        // First we enter the error state, since we need to show the error animation/text. The
+        // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+        assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
     }
 
     @Test
     public void testFingerprintOnlyStartsOnFirstError() {
         mFaceToFpView.onDialogAnimatedIn();
-        verify(mFaceToFpView.mIconController)
+        verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
 
         mFaceToFpView.onDialogAnimatedIn();
@@ -260,11 +271,6 @@
         protected int getDelayAfterAuthenticatedDurationMs() {
             return 0;
         }
-
-        @Override
-        protected IconController createUdfpsIconController() {
-            return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
-        }
     }
 
     private class MockInjector extends AuthBiometricView.Injector {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
index 043bd5c..b93381d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
@@ -62,7 +62,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mFaceView = new TestableFaceView(mContext);
-        mFaceView.mIconController = mock(TestableFaceView.TestableIconController.class);
+        mFaceView.mFaceIconController = mock(TestableFaceView.TestableIconController.class);
         mFaceView.setCallback(mCallback);
 
         mFaceView.mNegativeButton = mNegativeButton;
@@ -78,18 +78,18 @@
     @Test
     public void testStateUpdated_whenDialogAnimatedIn() {
         mFaceView.onDialogAnimatedIn();
-        verify(mFaceView.mIconController)
+        verify(mFaceView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
     }
 
     @Test
     public void testIconUpdatesState_whenDialogStateUpdated() {
         mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATING);
-        verify(mFaceView.mIconController)
+        verify(mFaceView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
 
         mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
-        verify(mFaceView.mIconController).updateState(
+        verify(mFaceView.mFaceIconController).updateState(
                 eq(AuthBiometricFaceView.STATE_AUTHENTICATING),
                 eq(AuthBiometricFaceView.STATE_AUTHENTICATED));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index bd518ff..f8e38e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -199,6 +200,7 @@
     }
 
     @Test
+    @Ignore("flaky, b/189031816")
     public void testError_sendsActionError() {
         initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
         final String testError = "testError";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index f53dddb..9098e44 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -62,6 +63,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.Execution;
 import com.android.systemui.util.concurrency.FakeExecution;
@@ -143,6 +145,8 @@
     private DisplayManager mDisplayManager;
     @Mock
     private Handler mHandler;
+    @Mock
+    private ConfigurationController mConfigurationController;
 
     private FakeExecutor mFgExecutor;
 
@@ -150,6 +154,10 @@
     @Mock
     private UdfpsView mUdfpsView;
     @Mock
+    private UdfpsEnrollView mEnrollView;
+    @Mock
+    private UdfpsKeyguardView mKeyguardView;
+    @Mock
     private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
     @Mock
     private TypedArray mBrightnessValues;
@@ -171,7 +179,13 @@
         setUpResources();
         mExecution = new FakeExecution();
 
-        when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
+        when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
+                .thenReturn(mUdfpsView);
+        when(mLayoutInflater.inflate(R.layout.udfps_enroll_view, null))
+                .thenReturn(mEnrollView); // for showOverlay REASON_ENROLL_ENROLLING
+        when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view, null))
+                .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
+        when(mEnrollView.getContext()).thenReturn(mContext);
         final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
 
         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
@@ -214,7 +228,8 @@
                 mKeyguardStateController,
                 mKeyguardBypassController,
                 mDisplayManager,
-                mHandler);
+                mHandler,
+                mConfigurationController);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -264,6 +279,75 @@
     }
 
     @Test
+    public void onActionMove_dozing_setDeviceEntryIntent() throws RemoteException {
+        // GIVEN the current animation is UdfpsKeyguardViewController and device IS dozing
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN device entry intent is never to true b/c device was dozing on touch
+        verify(mKeyguardBypassController, never()).setUserHasDeviceEntryIntent(true);
+    }
+
+    @Test
+    public void onActionMove_onKeyguard_setDeviceEntryIntent() throws RemoteException {
+        // GIVEN the current animation is UdfpsKeyguardViewController and device isn't dozing
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN device entry intent is set to true
+        verify(mKeyguardBypassController).setUserHasDeviceEntryIntent(true);
+    }
+
+    @Test
+    public void onActionMove_onEnrollment_neverSetDeviceEntryIntent() throws RemoteException {
+        // GIVEN the current animation is UdfpsEnrollViewController
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(
+                mock(UdfpsEnrollViewController.class));
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN device entry intent is never set
+        verify(mKeyguardBypassController, never()).setUserHasDeviceEntryIntent(anyBoolean());
+    }
+
+    @Test
     public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 57c57ec..cc34c30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import org.junit.Before;
@@ -77,6 +78,8 @@
     @Mock
     private KeyguardViewMediator mKeyguardViewMediator;
     @Mock
+    private ConfigurationController mConfigurationController;
+    @Mock
     private UdfpsController mUdfpsController;
 
     private UdfpsKeyguardViewController mController;
@@ -111,6 +114,7 @@
                 mDumpManager,
                 mKeyguardViewMediator,
                 mLockscreenShadeTransitionController,
+                mConfigurationController,
                 mUdfpsController);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
index e98cf1f..a22322f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -19,12 +19,13 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -36,6 +37,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.lang.ref.WeakReference;
@@ -44,7 +46,7 @@
 @RunWith(AndroidTestingRunner.class)
 public class CommunalHostViewControllerTest extends SysuiTestCase {
     @Mock
-    private Context mContext;
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     @Mock
     private KeyguardStateController mKeyguardStateController;
@@ -67,9 +69,13 @@
         MockitoAnnotations.initMocks(this);
 
         when(mKeyguardStateController.isShowing()).thenReturn(true);
+        when(mCommunalView.isAttachedToWindow()).thenReturn(true);
 
-        mController = new CommunalHostViewController(mFakeExecutor, mKeyguardStateController,
-                mStatusBarStateController, mCommunalView);
+        mController = new CommunalHostViewController(mFakeExecutor, mKeyguardUpdateMonitor,
+                mKeyguardStateController, mStatusBarStateController, mCommunalView);
+        mController.init();
+        mFakeExecutor.runAllReady();
+        Mockito.clearInvocations(mCommunalView);
     }
 
     @Test
@@ -92,4 +98,58 @@
         mFakeExecutor.runAllReady();
         verify(mCommunalView).setVisibility(View.INVISIBLE);
     }
+
+    @Test
+    public void testHideOnBouncer() {
+        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
+                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+
+        // Capture callback value for later use.
+        verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
+
+        // Establish a visible communal view.
+        mController.show(new WeakReference<>(mCommunalSource));
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.VISIBLE);
+        Mockito.clearInvocations(mCommunalView);
+
+        // Trigger bouncer.
+        Mockito.clearInvocations(mCommunalView);
+        callbackCapture.getValue().onKeyguardBouncerChanged(true);
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.INVISIBLE);
+
+        // Hide bouncer
+        Mockito.clearInvocations(mCommunalView);
+        callbackCapture.getValue().onKeyguardBouncerChanged(false);
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.VISIBLE);
+    }
+
+    @Test
+    public void testHideOnOcclude() {
+        ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
+                ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+
+        // Capture callback value for later use.
+        verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
+
+        // Establish a visible communal view.
+        mController.show(new WeakReference<>(mCommunalSource));
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.VISIBLE);
+        Mockito.clearInvocations(mCommunalView);
+
+        // Occlude.
+        Mockito.clearInvocations(mCommunalView);
+        callbackCapture.getValue().onKeyguardOccludedChanged(true);
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.INVISIBLE);
+
+        // Unocclude.
+        Mockito.clearInvocations(mCommunalView);
+        callbackCapture.getValue().onKeyguardOccludedChanged(false);
+        mFakeExecutor.runAllReady();
+        verify(mCommunalView).setVisibility(View.VISIBLE);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/service/CommunalSourcePrimerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/service/CommunalSourcePrimerTest.java
new file mode 100644
index 0000000..95ab5cb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/service/CommunalSourcePrimerTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.communal.service;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.res.Resources;
+import android.os.IBinder;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.communal.CommunalSourceMonitor;
+import com.android.systemui.shared.communal.ICommunalSource;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class CommunalSourcePrimerTest extends SysuiTestCase {
+    private static final String TEST_COMPONENT_NAME = "com.google.tests/.CommualService";
+    private static final ComponentName TEST_COMPONENT =
+            ComponentName.unflattenFromString(TEST_COMPONENT_NAME);
+    private static final int MAX_RETRIES = 5;
+    private static final int RETRY_DELAY_MS = 1000;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private Resources mResources;
+
+    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+    @Mock
+    private CommunalSourceMonitor mCommunalSourceMonitor;
+
+    @Mock
+    private CommunalSourceImpl.Factory mCommunalSourceFactory;
+
+    @Mock
+    private CommunalSourceImpl mCommunalSourceImpl;
+
+    @Mock
+    private IBinder mServiceProxy;
+
+    private CommunalSourcePrimer mPrimer;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getInteger(R.integer.config_communalSourceMaxReconnectAttempts))
+                .thenReturn(MAX_RETRIES);
+        when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
+                .thenReturn(RETRY_DELAY_MS);
+        when(mResources.getString(R.string.config_communalSourceComponent))
+                .thenReturn(TEST_COMPONENT_NAME);
+        when(mCommunalSourceFactory.create(any(ICommunalSource.class)))
+                .thenReturn(mCommunalSourceImpl);
+
+        mPrimer = new CommunalSourcePrimer(mContext, mResources, mFakeExecutor,
+                mCommunalSourceMonitor, mCommunalSourceFactory);
+    }
+
+    @Test
+    public void testNoConnectWithEmptyComponent() {
+        when(mResources.getString(R.string.config_communalSourceComponent)).thenReturn(null);
+        final CommunalSourcePrimer emptyComponentPrimer = new CommunalSourcePrimer(mContext,
+                mResources, mFakeExecutor, mCommunalSourceMonitor, mCommunalSourceFactory);
+
+        emptyComponentPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+        // When there is no component, we should not register any broadcast receives or bind to
+        // any service
+        verify(mContext, times(0))
+                .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+        verify(mContext, times(0)).bindService(any(Intent.class), anyInt(),
+                any(Executor.class), any(ServiceConnection.class));
+    }
+
+    private ServiceConnection givenOnBootCompleted(boolean bindSucceed) {
+        ArgumentCaptor<ServiceConnection> connectionCapture =
+                ArgumentCaptor.forClass(ServiceConnection.class);
+
+        when(mContext.bindService(any(Intent.class), anyInt(), any(Executor.class),
+                any(ServiceConnection.class))).thenReturn(bindSucceed);
+
+        mPrimer.onBootCompleted();
+        mFakeExecutor.runAllReady();
+
+        verify(mContext).bindService(any(Intent.class), anyInt(), any(Executor.class),
+                connectionCapture.capture());
+
+        // Simulate successful connection.
+        return connectionCapture.getValue();
+    }
+
+    @Test
+    public void testConnect() {
+        final ServiceConnection connection = givenOnBootCompleted(true);
+
+        // Simulate successful connection.
+        connection.onServiceConnected(TEST_COMPONENT, mServiceProxy);
+
+        // Verify source created and monitor informed.
+        verify(mCommunalSourceFactory).create(any(ICommunalSource.class));
+        verify(mCommunalSourceMonitor).setSource(mCommunalSourceImpl);
+    }
+
+    @Test
+    public void testRetryOnBindFailure() {
+        // Fail to bind on connection.
+        givenOnBootCompleted(false);
+
+        // Verify attempts happen. Note that we account for the retries plus initial attempt, which
+        // is not scheduled.
+        for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
+            verify(mContext, times(1)).bindService(any(Intent.class),
+                    anyInt(), any(Executor.class), any(ServiceConnection.class));
+            clearInvocations(mContext);
+            mFakeExecutor.advanceClockToNext();
+            mFakeExecutor.runAllReady();
+        }
+
+        // Verify no more attempts occur.
+        verify(mContext, times(0)).bindService(any(Intent.class), anyInt(),
+                any(Executor.class), any(ServiceConnection.class));
+
+        // Verify source is not created and monitor is not informed.
+        verify(mCommunalSourceFactory, times(0))
+                .create(any(ICommunalSource.class));
+        verify(mCommunalSourceMonitor, times(0))
+                .setSource(any(CommunalSourceImpl.class));
+    }
+
+    @Test
+    public void testAttemptOnPackageChange() {
+        ArgumentCaptor<BroadcastReceiver> receiverCapture =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+        // Fail to bind initially.
+        givenOnBootCompleted(false);
+
+        // Capture broadcast receiver.
+        verify(mContext).registerReceiver(receiverCapture.capture(), any(IntentFilter.class));
+
+        clearInvocations(mContext);
+
+        // Inform package has been added.
+        receiverCapture.getValue().onReceive(mContext, new Intent());
+
+        // Verify bind has been attempted.
+        verify(mContext, times(1)).bindService(any(Intent.class), anyInt(),
+                any(Executor.class), any(ServiceConnection.class));
+    }
+
+    @Test
+    public void testRetryOnServiceDisconnected() {
+        verifyConnectionFailureReconnect(v -> v.onServiceDisconnected(TEST_COMPONENT));
+    }
+
+    @Test
+    public void testRetryOnBindingDied() {
+        verifyConnectionFailureReconnect(v -> v.onBindingDied(TEST_COMPONENT));
+    }
+
+    private void verifyConnectionFailureReconnect(ConnectionHandler connectionHandler) {
+        // Fail to bind on connection.
+        final ServiceConnection connection = givenOnBootCompleted(false);
+
+        clearInvocations(mContext, mCommunalSourceMonitor);
+
+        connectionHandler.onConnectionMade(connection);
+
+        // Ensure source is cleared.
+        verify(mCommunalSourceMonitor).setSource(null);
+
+        // Ensure request made to bind. This is not a reattempt so it should happen in the same
+        // execution loop.
+        verify(mContext).bindService(any(Intent.class), anyInt(), any(Executor.class),
+                any(ServiceConnection.class));
+    }
+
+    interface ConnectionHandler {
+        void onConnectionMade(ServiceConnection connection);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
index 223714c..7bc5f86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
@@ -32,6 +32,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.wrapper.BuildInfo;
 
 import org.junit.Before;
@@ -43,6 +44,7 @@
 public class FeatureFlagReaderTest extends SysuiTestCase {
     @Mock private Resources mResources;
     @Mock private BuildInfo mBuildInfo;
+    @Mock private PluginManager mPluginManager;
     @Mock private SystemPropertiesHelper mSystemPropertiesHelper;
 
     private FeatureFlagReader mReader;
@@ -63,7 +65,8 @@
     private void initialize(boolean isDebuggable, boolean isOverrideable) {
         when(mBuildInfo.isDebuggable()).thenReturn(isDebuggable);
         when(mResources.getBoolean(R.bool.are_flags_overrideable)).thenReturn(isOverrideable);
-        mReader = new FeatureFlagReader(mResources, mBuildInfo, mSystemPropertiesHelper);
+        mReader = new FeatureFlagReader(
+                mResources, mBuildInfo, mPluginManager, mSystemPropertiesHelper);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
new file mode 100644
index 0000000..1a96178
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.FlagReaderPlugin;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class FeatureFlagsTest extends SysuiTestCase {
+
+    @Mock FeatureFlagReader mFeatureFlagReader;
+
+    private FeatureFlags mFeatureFlags;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        mFeatureFlags = new FeatureFlags(mFeatureFlagReader, getContext());
+    }
+
+    @Test
+    public void testAddListener() {
+        Flag<?> flag = new BooleanFlag(1);
+        mFeatureFlags.addFlag(flag);
+
+        // Assert and capture that a plugin listener was added.
+        ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor =
+                ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class);
+
+        verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
+        FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue();
+
+        // Signal a change. No listeners, so no real effect.
+        pluginListener.onFlagChanged(flag.getId());
+
+        // Add a listener for the flag
+        final Flag<?>[] changedFlag = {null};
+        FeatureFlags.Listener listener = f -> changedFlag[0] = f;
+        mFeatureFlags.addFlagListener(flag, listener);
+
+        // No changes seen yet.
+        assertThat(changedFlag[0]).isNull();
+
+        // Signal a change.
+        pluginListener.onFlagChanged(flag.getId());
+
+        // Assert that the change was for the correct flag.
+        assertThat(changedFlag[0]).isEqualTo(flag);
+    }
+
+    @Test
+    public void testRemoveListener() {
+        Flag<?> flag = new BooleanFlag(1);
+        mFeatureFlags.addFlag(flag);
+
+        // Assert and capture that a plugin listener was added.
+        ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor =
+                ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class);
+
+        verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
+        FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue();
+
+        // Add a listener for the flag
+        final Flag<?>[] changedFlag = {null};
+        FeatureFlags.Listener listener = f -> changedFlag[0] = f;
+        mFeatureFlags.addFlagListener(flag, listener);
+
+        // Signal a change.
+        pluginListener.onFlagChanged(flag.getId());
+
+        // Assert that the change was for the correct flag.
+        assertThat(changedFlag[0]).isEqualTo(flag);
+
+        changedFlag[0] = null;
+
+        // Now remove the listener.
+        mFeatureFlags.removeFlagListener(flag, listener);
+        // Signal a change.
+        pluginListener.onFlagChanged(flag.getId());
+        // Assert that the change was not triggered
+        assertThat(changedFlag[0]).isNull();
+
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java
new file mode 100644
index 0000000..25c3028
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@SmallTest
+public class FlagsTest extends SysuiTestCase {
+
+    @Test
+    public void testDuplicateFlagIdCheckWorks() {
+        List<Pair<String, Flag<?>>> flags = collectFlags(DuplicateFlagContainer.class);
+        Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags);
+
+        assertWithMessage(generateAssertionMessage(duplicates))
+                .that(duplicates.size()).isEqualTo(2);
+    }
+
+    @Test
+    public void testNoDuplicateFlagIds() {
+        List<Pair<String, Flag<?>>> flags = collectFlags(Flags.class);
+        Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags);
+
+        assertWithMessage(generateAssertionMessage(duplicates))
+                .that(duplicates.size()).isEqualTo(0);
+    }
+
+    private String generateAssertionMessage(Map<Integer, List<String>> duplicates) {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("Duplicate flag keys found: {");
+        for (int id : duplicates.keySet()) {
+            stringBuilder
+                    .append(" ")
+                    .append(id)
+                    .append(": [")
+                    .append(String.join(", ", duplicates.get(id)))
+                    .append("]");
+        }
+        stringBuilder.append(" }");
+
+        return stringBuilder.toString();
+    }
+
+    private List<Pair<String, Flag<?>>> collectFlags(Class<?> clz) {
+        List<Pair<String, Flag<?>>> flags = new ArrayList<>();
+
+        Field[] fields = clz.getFields();
+
+        for (Field field : fields) {
+            Class<?> t = field.getType();
+            if (Flag.class.isAssignableFrom(t)) {
+                try {
+                    flags.add(Pair.create(field.getName(), (Flag<?>) field.get(null)));
+                } catch (IllegalAccessException e) {
+                    // no-op
+                }
+            }
+        }
+
+        return flags;
+    }
+
+    private Map<Integer, List<String>> groupDuplicateFlags(List<Pair<String, Flag<?>>> flags) {
+        Map<Integer, List<String>> grouping = new HashMap<>();
+
+        for (Pair<String, Flag<?>> flag : flags) {
+            grouping.putIfAbsent(flag.second.getId(), new ArrayList<>());
+            grouping.get(flag.second.getId()).add(flag.first);
+        }
+
+        Map<Integer, List<String>> result = new HashMap<>();
+        for (Integer id : grouping.keySet()) {
+            if (grouping.get(id).size() > 1) {
+                result.put(id, grouping.get(id));
+            }
+        }
+
+        return result;
+    }
+
+    private static class DuplicateFlagContainer {
+        public static final BooleanFlag A_FLAG = new BooleanFlag(0);
+        public static final BooleanFlag B_FLAG = new BooleanFlag(0);
+        public static final StringFlag C_FLAG = new StringFlag(0);
+
+        public static final BooleanFlag D_FLAG = new BooleanFlag(1);
+
+        public static final DoubleFlag E_FLAG = new DoubleFlag(3);
+        public static final DoubleFlag F_FLAG = new DoubleFlag(3);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 1dacc62..31d70f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -33,8 +34,9 @@
 import android.app.trust.TrustManager;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -65,7 +67,7 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@TestableLooper.RunWithLooper
 @SmallTest
 public class KeyguardViewMediatorTest extends SysuiTestCase {
     private KeyguardViewMediator mViewMediator;
@@ -160,4 +162,29 @@
         mViewMediator.onDozeAmountChanged(1f, 1f);
         assertFalse(mViewMediator.isAnimatingScreenOff());
     }
+
+    @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() {
+        // When showing and provisioned
+        mViewMediator.onSystemReady();
+        when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+        mViewMediator.setShowingLocked(true);
+
+        // and a SIM becomes locked and requires a PIN
+        mViewMediator.mUpdateCallback.onSimStateChanged(
+                1 /* subId */,
+                0 /* slotId */,
+                TelephonyManager.SIM_STATE_PIN_REQUIRED);
+
+        // and the keyguard goes away
+        mViewMediator.setShowingLocked(false);
+        when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+        mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false);
+
+        TestableLooper.get(this).processAllMessages();
+
+        // then make sure it comes back
+        verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 79b0dd0..8cc2776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -69,7 +69,7 @@
         whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
                 .thenReturn(true)
         whenever(mediaHost.hostView).thenReturn(hostView)
-
+        hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
         keyguardMediaController = KeyguardMediaController(
             mediaHost,
             bypassController,
@@ -79,6 +79,7 @@
             configurationController
         )
         keyguardMediaController.attachSinglePaneContainer(mediaHeaderView)
+        keyguardMediaController.useSplitShade = false
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 8fd2a32..3ea57be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -142,6 +142,8 @@
 
     @Test
     public void testCreateNavigationBarsIncludeDefaultTrue() {
+        // Tablets may be using taskbar and the logic is different
+        mNavigationBarController.mIsTablet = false;
         doNothing().when(mNavigationBarController).createNavigationBar(any(), any(), any());
 
         mNavigationBarController.createNavigationBars(true, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
new file mode 100644
index 0000000..9378b2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
@@ -0,0 +1,91 @@
+package com.android.systemui.qs
+
+import com.android.systemui.R
+import android.os.UserManager
+import android.view.LayoutInflater
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.FakeMetricsLogger
+import com.android.systemui.Dependency
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.globalactions.GlobalActionsDialogLite
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.utils.leaks.FakeTunerService
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class QSFooterActionsControllerTest : LeakCheckedTest() {
+    @Mock
+    private lateinit var userManager: UserManager
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
+    @Mock
+    private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock
+    private lateinit var userInfoController: UserInfoController
+    @Mock
+    private lateinit var qsPanelController: QSPanelController
+    @Mock
+    private lateinit var multiUserSwitchController: MultiUserSwitchController
+    @Mock
+    private lateinit var globalActionsDialog: GlobalActionsDialogLite
+    @Mock
+    private lateinit var uiEventLogger: UiEventLogger
+    @Mock
+    private lateinit var controller: QSFooterActionsController
+
+    private val metricsLogger: MetricsLogger = FakeMetricsLogger()
+    private lateinit var view: QSFooterActionsView
+    private val falsingManager: FalsingManagerFake = FalsingManagerFake()
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
+        val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
+
+        view = LayoutInflater.from(context)
+                .inflate(R.layout.qs_footer_actions, null) as QSFooterActionsView
+
+        controller = QSFooterActionsController(view, qsPanelController, activityStarter,
+                userManager, userInfoController, multiUserSwitchController,
+                deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
+                globalActionsDialog, uiEventLogger, showPMLiteButton = true)
+        controller.init()
+        controller.onViewAttached()
+    }
+
+    @Test
+    fun testLogPowerMenuClick() {
+        controller.expanded = true
+        falsingManager.setFalseTap(false)
+
+        view.findViewById<View>(R.id.pm_lite).performClick()
+        // Verify clicks are logged
+        verify(uiEventLogger, Mockito.times(1))
+                .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
+    }
+
+    @Test
+    fun testSettings_UserNotSetup() {
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+        view.findViewById<View>(R.id.settings_button).performClick()
+        // Verify Settings wasn't launched.
+        verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean())
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 6f7bf3b..8c6c358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -18,16 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ClipData;
 import android.content.ClipboardManager;
-import android.os.UserManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
@@ -35,21 +30,8 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.testing.FakeMetricsLogger;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.globalactions.GlobalActionsDialogLite;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitchController;
-import com.android.systemui.statusbar.phone.SettingsButton;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.utils.leaks.FakeTunerService;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
@@ -67,14 +49,6 @@
     @Mock
     private QSFooterView mView;
     @Mock
-    private UserManager mUserManager;
-    @Mock
-    private ActivityStarter mActivityStarter;
-    @Mock
-    private DeviceProvisionedController mDeviceProvisionedController;
-    @Mock
-    private UserInfoController mUserInfoController;
-    @Mock
     private UserTracker mUserTracker;
     @Mock
     private QSPanelController mQSPanelController;
@@ -82,36 +56,19 @@
     private ClipboardManager mClipboardManager;
     @Mock
     private QuickQSPanelController mQuickQSPanelController;
-    private FakeTunerService mFakeTunerService;
-    private MetricsLogger mMetricsLogger = new FakeMetricsLogger();
-    private FalsingManagerFake mFalsingManager;
-
-    @Mock
-    private SettingsButton mSettingsButton;
     @Mock
     private TextView mBuildText;
     @Mock
-    private View mEdit;
-    @Mock
-    private MultiUserSwitchController mMultiUserSwitchController;
-    @Mock
-    private View mPowerMenuLiteView;
-    @Mock
-    private GlobalActionsDialogLite mGlobalActionsDialog;
-    @Mock
-    private UiEventLogger mUiEventLogger;
+    private QSFooterActionsController mQSFooterActionsController;
 
     private QSFooterViewController mController;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mFalsingManager = new FalsingManagerFake();
 
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
 
-        mFakeTunerService = (FakeTunerService) Dependency.get(TunerService.class);
-
         mContext.addMockSystemService(ClipboardManager.class, mClipboardManager);
 
         when(mView.getContext()).thenReturn(mContext);
@@ -119,16 +76,10 @@
         when(mUserTracker.getUserContext()).thenReturn(mContext);
 
         when(mView.isAttachedToWindow()).thenReturn(true);
-        when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton);
         when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
-        when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
-        when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
 
-        mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
-                mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
-                mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
-                mMetricsLogger, mFalsingManager, false, mGlobalActionsDialog,
-                mUiEventLogger);
+        mController = new QSFooterViewController(mView, mUserTracker, mQSPanelController,
+                mQuickQSPanelController, mQSFooterActionsController);
 
         mController.init();
     }
@@ -148,40 +99,4 @@
         verify(mClipboardManager).setPrimaryClip(captor.capture());
         assertThat(captor.getValue().getItemAt(0).getText()).isEqualTo(text);
     }
-
-    @Test
-    public void testSettings_UserNotSetup() {
-        ArgumentCaptor<View.OnClickListener> onClickCaptor =
-                ArgumentCaptor.forClass(View.OnClickListener.class);
-        verify(mSettingsButton).setOnClickListener(onClickCaptor.capture());
-
-        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
-
-        onClickCaptor.getValue().onClick(mSettingsButton);
-        // Verify Settings wasn't launched.
-        verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
-    }
-
-    @Test
-    public void testLogPowerMenuClick() {
-        // Enable power menu button
-        mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
-                mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
-                mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
-                mMetricsLogger, new FalsingManagerFake(), true, mGlobalActionsDialog,
-                mUiEventLogger);
-        mController.init();
-        mController.setExpanded(true);
-        mFalsingManager.setFalseTap(false);
-
-        ArgumentCaptor<View.OnClickListener> onClickCaptor =
-                ArgumentCaptor.forClass(View.OnClickListener.class);
-        verify(mPowerMenuLiteView).setOnClickListener(onClickCaptor.capture());
-
-        onClickCaptor.getValue().onClick(mPowerMenuLiteView);
-
-        // Verify clicks are logged
-        verify(mUiEventLogger, times(1))
-                .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index ad16e9d..109721f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -186,6 +186,7 @@
                 mQQSMediaHost,
                 mBypassController,
                 mQsComponentFactory,
-                mFalsingManager);
+                mFalsingManager,
+                mock(DumpManager.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
new file mode 100644
index 0000000..56f2905
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import com.google.common.truth.Truth.assertThat
+
+import androidx.test.filters.SmallTest
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class QSPanelSwitchToParentTest : SysuiTestCase() {
+
+    private lateinit var parent1: FrameLayout
+    private lateinit var parent2: FrameLayout
+
+    private lateinit var movingView: View
+
+    private lateinit var view1A: View
+    private lateinit var view1B: View
+    private lateinit var view1C: View
+
+    private lateinit var view2A: View
+    private lateinit var view2B: View
+    private lateinit var view2C: View
+
+    @Before
+    fun setUp() {
+        parent1 = FrameLayout(mContext)
+        parent2 = FrameLayout(mContext)
+
+        movingView = View(mContext)
+
+        view1A = View(mContext)
+        parent1.addView(view1A)
+        view1B = View(mContext)
+        parent1.addView(view1B)
+        view1C = View(mContext)
+        parent1.addView(view1C)
+
+        view2A = View(mContext)
+        parent2.addView(view2A)
+        view2B = View(mContext)
+        parent2.addView(view2B)
+        view2C = View(mContext)
+        parent2.addView(view2C)
+    }
+
+    @Test
+    fun testNullTargetNoInteractions() {
+        QSPanel.switchToParent(movingView, null, -1, "")
+
+        assertThat(movingView.parent).isNull()
+    }
+
+    @Test
+    fun testMoveToEndNoParent() {
+        QSPanel.switchToParent(movingView, parent2, -1, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, view2B, view2C, movingView
+        )
+    }
+
+    @Test
+    fun testMoveToEndDifferentParent() {
+        parent1.addView(movingView, 0)
+
+        QSPanel.switchToParent(movingView, parent2, -1, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, view2B, view2C, movingView
+        )
+    }
+
+    @Test
+    fun testMoveToEndSameParent() {
+        parent2.addView(movingView, 0)
+
+        QSPanel.switchToParent(movingView, parent2, -1, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, view2B, view2C, movingView
+        )
+    }
+
+    @Test
+    fun testMoveToMiddleFromNoParent() {
+        QSPanel.switchToParent(movingView, parent2, 1, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, movingView, view2B, view2C
+        )
+    }
+
+    @Test
+    fun testMoveToMiddleDifferentParent() {
+        parent1.addView(movingView, 1)
+
+        QSPanel.switchToParent(movingView, parent2, 2, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, view2B, movingView, view2C
+        )
+    }
+
+    @Test
+    fun testMoveToMiddleSameParent() {
+        parent2.addView(movingView, 0)
+
+        QSPanel.switchToParent(movingView, parent2, 1, "")
+
+        assertThat(parent1.childrenList).containsExactly(
+                view1A, view1B, view1C
+        )
+        assertThat(parent2.childrenList).containsExactly(
+                view2A, movingView, view2B, view2C
+        )
+    }
+
+    private val ViewGroup.childrenList: List<View>
+        get() = children.toList()
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index a83a5e1..3500c18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -69,6 +69,8 @@
     @Mock
     private lateinit var mQSTileView: QSTileView
 
+    private lateinit var mFooter: View
+
     @Before
     @Throws(Exception::class)
     fun setup() {
@@ -81,7 +83,8 @@
             mQsPanel = QSPanel(mContext, null)
             mQsPanel.initialize()
             // QSPanel inflates a footer inside of it, mocking it here
-            mQsPanel.addView(LinearLayout(mContext).apply { id = R.id.qs_footer })
+            mFooter = LinearLayout(mContext).apply { id = R.id.qs_footer }
+            mQsPanel.addView(mFooter)
             mQsPanel.onFinishInflate()
             mQsPanel.setSecurityFooter(View(mContext), false)
             mQsPanel.setHeaderContainer(LinearLayout(mContext))
@@ -125,7 +128,10 @@
             mQsPanel.isExpanded = true
         }
 
-        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+        // After mFooter
+        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(
+                mQsPanel.indexOfChild(mFooter) + 1
+        )
     }
 
     @Test
@@ -137,7 +143,10 @@
             mQsPanel.isExpanded = true
         }
 
-        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+        // After mFooter
+        assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(
+                mQsPanel.indexOfChild(mFooter) + 1
+        )
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index f208b80..9e97f80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -44,7 +44,6 @@
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.CollectionUtils;
@@ -64,22 +63,18 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.settings.SecureSettings;
 
-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 org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -133,16 +128,9 @@
     private Handler mHandler;
     private TestableLooper mLooper;
     private QSTileHost mQSTileHost;
-    MockitoSession mMockingSession = null;
 
     @Before
     public void setUp() {
-        // TODO(b/174753536): Remove the mMockingSession when
-        // FeatureFlagUtils.SETTINGS_PROVIDER_MODEL is removed.
-        mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
-                .mockStatic(FeatureFlags.class).startMocking();
-        ExtendedMockito.doReturn(false)
-                .when(() -> FeatureFlags.isProviderModelSettingEnabled(mContext));
         MockitoAnnotations.initMocks(this);
         mLooper = TestableLooper.get(this);
         mHandler = new Handler(mLooper.getLooper());
@@ -156,13 +144,6 @@
                 .thenReturn("");
     }
 
-    @After
-    public void tearDown() throws Exception {
-        if (mMockingSession != null) {
-            mMockingSession.finishMocking();
-        }
-    }
-
     private void setUpTileFactory() {
         when(mMockState.toString()).thenReturn(MOCK_STATE_STRING);
         // Only create this kind of tiles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt
index f8373ff..de1d86b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt
@@ -19,13 +19,15 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.brightness.BrightnessController
+import com.android.systemui.statusbar.policy.BrightnessMirrorController
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.Mock
-import org.mockito.Mockito.verify
 import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.never
+import org.mockito.Mockito.mock
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
@@ -104,4 +106,13 @@
 
         verify(brightnessController, never()).registerCallbacks()
     }
+
+    @Test
+    fun testMirrorIsSetWhenSliderIsShown() {
+        val mirrorController = mock(BrightnessMirrorController::class.java)
+        quickQSBrightnessController.setMirror(mirrorController)
+        quickQSBrightnessController.refreshVisibility(shouldUseSplitNotificationShade = true)
+
+        verify(brightnessController).setMirror(mirrorController)
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 62ac72e..66a006f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.plugins.qs.QSTileView
 import com.android.systemui.qs.customize.QSCustomizerController
 import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 8b7e20e..b34433c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -23,8 +23,10 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.colorextraction.SysuiColorExtractor
 import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.privacy.OngoingPrivacyChip
 import com.android.systemui.privacy.PrivacyDialogController
@@ -32,7 +34,6 @@
 import com.android.systemui.privacy.logging.PrivacyLogger
 import com.android.systemui.qs.carrier.QSCarrierGroup
 import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.policy.Clock
@@ -49,9 +50,9 @@
 import org.mockito.Answers
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -93,6 +94,8 @@
     @Mock
     private lateinit var variableDateViewController: VariableDateViewController
     @Mock
+    private lateinit var batteryMeterViewController: BatteryMeterViewController
+    @Mock
     private lateinit var clock: Clock
     @Mock
     private lateinit var variableDateView: VariableDateView
@@ -144,7 +147,8 @@
                 privacyDialogController,
                 qsExpansionPathInterpolator,
                 featureFlags,
-                variableDateViewControllerFactory
+                variableDateViewControllerFactory,
+                batteryMeterViewController
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 72c7ddd..126b332 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -37,8 +37,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.CarrierTextManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
 import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4a1411a..4efcc5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -45,13 +45,11 @@
 import android.testing.TestableLooper;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
 import android.view.View;
 
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.logging.InstanceId;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -60,11 +58,9 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -74,8 +70,6 @@
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -114,7 +108,6 @@
     private PackageManager mPackageManager;
     @Mock
     private UserTracker mUserTracker;
-    @Mock private FeatureFlags mFeatureFlags;
     @Captor
     private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
 
@@ -122,18 +115,10 @@
     private TileQueryHelper mTileQueryHelper;
     private FakeExecutor mMainExecutor;
     private FakeExecutor mBgExecutor;
-    MockitoSession mMockingSession = null;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        // TODO(b/174753536): Remove the mMockingSession when
-        // FeatureFlagUtils.SETTINGS_PROVIDER_MODEL is removed.
-        mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
-                .mockStatic(FeatureFlagUtils.class).startMocking();
-        ExtendedMockito.doReturn(false).when(() -> FeatureFlagUtils.isEnabled(mContext,
-                FeatureFlagUtils.SETTINGS_PROVIDER_MODEL));
-
         mContext.setMockPackageManager(mPackageManager);
 
         mState = new QSTile.State();
@@ -153,17 +138,10 @@
         mMainExecutor = new FakeExecutor(clock);
         mBgExecutor = new FakeExecutor(clock);
         mTileQueryHelper = new TileQueryHelper(
-                mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
+                mContext, mUserTracker, mMainExecutor, mBgExecutor);
         mTileQueryHelper.setListener(mListener);
     }
 
-    @After
-    public void tearDown() throws Exception {
-        if (mMockingSession != null) {
-            mMockingSession.finishMocking();
-        }
-    }
-
     @Test
     public void testIsFinished_falseBeforeQuerying() {
         assertFalse(mTileQueryHelper.isFinished());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index a8f6f53..2b9082d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -2,7 +2,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
@@ -11,6 +13,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.wifi.WifiUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.wifitrackerlib.WifiEntry;
 
@@ -28,51 +31,65 @@
 
     private static final String WIFI_TITLE = "Wi-Fi Title";
     private static final String WIFI_SUMMARY = "Wi-Fi Summary";
-    private InternetDialogController mInternetDialogController = mock(
-            InternetDialogController.class);
+
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private WifiEntry mWifiEntry;
+    @Mock
+    private InternetDialogController mInternetDialogController;
+    @Mock
+    private WifiUtils.InternetIconInjector mWifiIconInjector;
+
     private InternetAdapter mInternetAdapter;
     private InternetAdapter.InternetViewHolder mViewHolder;
-    @Mock
-    private WifiEntry mWifiEntry = mock(WifiEntry.class);
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInternetAdapter = new InternetAdapter(mInternetDialogController);
-        mViewHolder = (InternetAdapter.InternetViewHolder) mInternetAdapter
-                .onCreateViewHolder(new LinearLayout(mContext), 0);
+        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
+        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
         when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
         when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+
+        mInternetAdapter = new InternetAdapter(mInternetDialogController);
+        mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
+        when(mInternetDialogController.getInternetWifiEntry()).thenReturn(mInternetWifiEntry);
         when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
+        mViewHolder.mWifiIconInjector = mWifiIconInjector;
     }
 
     @Test
-    public void getItemCount_withApmOnWifiOnNoConnectedWifi_returnFour() {
+    public void getItemCount_withApmOnWifiOnNoInternetWifi_returnFour() {
+        // The preconditions WiFi ON is already in setUp()
+        when(mInternetDialogController.getInternetWifiEntry()).thenReturn(null);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
 
         assertThat(mInternetAdapter.getItemCount()).isEqualTo(4);
     }
 
     @Test
-    public void getItemCount_withApmOnWifiOnHasConnectedWifi_returnThree() {
-        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
-        when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
+    public void getItemCount_withApmOnWifiOnHasInternetWifi_returnThree() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
 
         assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
     }
 
     @Test
-    public void getItemCount_withApmOffWifiOnNoConnectedWifi_returnThree() {
+    public void getItemCount_withApmOffWifiOnNoInternetWifi_returnThree() {
+        // The preconditions WiFi ON is already in setUp()
+        when(mInternetDialogController.getInternetWifiEntry()).thenReturn(null);
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
 
         assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
     }
 
     @Test
-    public void getItemCount_withApmOffWifiOnHasConnectedWifi_returnTwo() {
-        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
-        when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
+    public void getItemCount_withApmOffWifiOnHasInternetWifi_returnTwo() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
         when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
 
         assertThat(mInternetAdapter.getItemCount()).isEqualTo(2);
@@ -99,4 +116,22 @@
         assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
     }
+
+    @Test
+    public void onBindViewHolder_bindDefaultWifiNetwork_getIconWithInternet() {
+        when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(false);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector).getIcon(eq(false) /* noInternet */, anyInt());
+    }
+
+    @Test
+    public void onBindViewHolder_bindNoDefaultWifiNetwork_getIconWithNoInternet() {
+        when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
+
+        mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+        verify(mWifiIconInjector).getIcon(eq(true) /* noInternet */, anyInt());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 68df19e..830fe5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -4,7 +4,9 @@
 
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -13,9 +15,9 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.wifi.ScanResult;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.telephony.ServiceState;
@@ -30,10 +32,13 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -60,16 +65,12 @@
     private static final String CONNECTED_TITLE = "Connected Wi-Fi Title";
     private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary";
 
-    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
-    private MockInternetDialogController mInternetDialogController;
-    private InternetDialogController.InternetDialogCallback mCallback =
-            mock(InternetDialogController.InternetDialogCallback.class);
-    private ActivityStarter mStarter = mock(ActivityStarter.class);
-    private WifiManager mWifiManager = mock(WifiManager.class);
-    private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class);
-    private TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
-    private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
     @Mock
     private Handler mHandler;
     @Mock
@@ -77,32 +78,41 @@
     @Mock
     private GlobalSettings mGlobalSettings;
     @Mock
-    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private KeyguardStateController mKeyguardStateController;
     @Mock
     private NetworkController.AccessPointController mAccessPointController;
     @Mock
     private WifiEntry mConnectedEntry;
     @Mock
-    private WifiInfo mWifiInfo;
-    @Mock
     private ServiceState mServiceState;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private WifiUtils.InternetIconInjector mWifiIconInjector;
+
+    private MockInternetDialogController mInternetDialogController;
+    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
-        when(mWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
-        mInternetDialogController = new MockInternetDialogController(mContext, mUiEventLogger,
-                mStarter, mAccessPointController, mSubscriptionManager, mTelephonyManager,
-                mWifiManager, mConnectivityManager, mHandler, mExecutor, mBroadcastDispatcher,
-                mKeyguardUpdateMonitor, mGlobalSettings);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+        when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
+        when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
+
+        mInternetDialogController = new MockInternetDialogController(mContext,
+                mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
+                mSubscriptionManager, mTelephonyManager, mWifiManager,
+                mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
+                mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController);
         mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
                 mInternetDialogController.mOnSubscriptionsChangedListener);
-        mInternetDialogController.onStart(mCallback);
+        mInternetDialogController.onStart(
+                mock(InternetDialogController.InternetDialogCallback.class));
         mInternetDialogController.mActivityStarter = mActivityStarter;
         mInternetDialogController.mConnectedEntry = mConnectedEntry;
+        mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
     }
 
     @Test
@@ -162,6 +172,16 @@
     }
 
     @Test
+    public void getSubtitleText_deviceLockedWithWifiOn_returnUnlockToViewNetworks() {
+        mInternetDialogController.setAirplaneModeEnabled(false);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
+                getResourcesString("unlock_to_view_networks")));
+    }
+
+    @Test
     public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
         mInternetDialogController.setAirplaneModeEnabled(false);
         when(mWifiManager.isWifiEnabled()).thenReturn(true);
@@ -199,35 +219,62 @@
     }
 
     @Test
-    public void getConnectedWifiTitle_withNoConnectedEntry_returnNull() {
+    public void getInternetWifiEntry_connectedEntryIsNull_returnNull() {
         mInternetDialogController.mConnectedEntry = null;
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiTitle(),
-                ""));
+        assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
     }
 
     @Test
-    public void getConnectedWifiTitle_withConnectedEntry_returnTitle() {
+    public void getInternetWifiEntry_connectedWifiIsNotDefaultNetwork_returnNull() {
+        when(mConnectedEntry.isDefaultNetwork()).thenReturn(false);
+
+        assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
+    }
+
+    @Test
+    public void getInternetWifiEntry_connectedWifiHasNotInternetAccess_returnNull() {
+        when(mConnectedEntry.hasInternetAccess()).thenReturn(false);
+
+        assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
+    }
+
+    @Test
+    public void getInternetWifiEntry_connectedEntryIsInternetWifi_returnConnectedEntry() {
+        // The preconditions have been set in setUp().
+        //   - The connected Wi-Fi entry have both default network and internet access conditions.
+
+        assertThat(mInternetDialogController.getInternetWifiEntry()).isEqualTo(mConnectedEntry);
+    }
+
+    @Test
+    public void getInternetWifiTitle_withNoConnectedWifiEntry_returnEmpty() {
+        mInternetDialogController.mConnectedEntry = null;
+
+        assertThat(mInternetDialogController.getInternetWifiTitle()).isEmpty();
+    }
+
+    @Test
+    public void getInternetWifiTitle_withInternetWifi_returnTitle() {
+        // The preconditions have been set in setUp().
+        //   - The connected Wi-Fi entry have both default network and internet access conditions.
         when(mConnectedEntry.getTitle()).thenReturn(CONNECTED_TITLE);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiTitle(),
-                CONNECTED_TITLE));
+        assertThat(mInternetDialogController.getInternetWifiTitle()).isEqualTo(CONNECTED_TITLE);
     }
 
     @Test
-    public void getConnectedWifiSummary_withNoConnectedEntry_returnNull() {
+    public void getInternetWifiSummary_withNoConnectedWifiEntry_returnEmpty() {
         mInternetDialogController.mConnectedEntry = null;
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiSummary(),
-                ""));
+        assertThat(mInternetDialogController.getInternetWifiSummary()).isEmpty();
     }
 
     @Test
-    public void getConnectedWifiSummary_withConnectedEntry_returnSummary() {
+    public void getInternetWifiSummary_withInternetWifi_returnSummary() {
         when(mConnectedEntry.getSummary(false)).thenReturn(CONNECTED_SUMMARY);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiSummary(),
-                CONNECTED_SUMMARY));
+        assertThat(mInternetDialogController.getInternetWifiSummary()).isEqualTo(CONNECTED_SUMMARY);
     }
 
     @Test
@@ -252,6 +299,17 @@
     }
 
     @Test
+    public void getWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() {
+        final Drawable drawable = mock(Drawable.class);
+        when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable);
+
+        mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
+
+        verify(mWifiIconInjector).getIcon(eq(false), anyInt());
+        verify(drawable).setTint(mContext.getColor(R.color.connected_network_primary_color));
+    }
+
+    @Test
     public void launchWifiNetworkDetailsSetting_withNoConnectedEntry_doNothing() {
         mInternetDialogController.mConnectedEntry = null;
 
@@ -270,6 +328,20 @@
         verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
     }
 
+    @Test
+    public void isDeviceLocked_keyguardIsUnlocked_returnFalse() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
+
+        assertThat(mInternetDialogController.isDeviceLocked()).isFalse();
+    }
+
+    @Test
+    public void isDeviceLocked_keyguardIsLocked_returnTrue() {
+        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
+
+        assertThat(mInternetDialogController.isDeviceLocked()).isTrue();
+    }
+
     private String getResourcesString(String name) {
         return mContext.getResources().getString(getResourcesId(name));
     }
@@ -290,10 +362,12 @@
                 @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
                 @Main Handler handler, @Main Executor mainExecutor,
                 BroadcastDispatcher broadcastDispatcher,
-                KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings) {
+                KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings,
+                KeyguardStateController keyguardStateController) {
             super(context, uiEventLogger, starter, accessPointController, subscriptionManager,
                     telephonyManager, wifiManager, connectivityManager, handler, mainExecutor,
-                    broadcastDispatcher, keyguardUpdateMonitor, globalSettings);
+                    broadcastDispatcher, keyguardUpdateMonitor, globalSettings,
+                    keyguardStateController);
             mGlobalSettings = globalSettings;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index a1a7e71..5a018f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -3,6 +3,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
@@ -11,12 +12,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.wifi.ScanResult;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.telephony.TelephonyManager;
@@ -32,7 +28,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.wifitrackerlib.WifiEntry;
 
 import org.junit.After;
@@ -41,6 +36,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
@@ -52,52 +48,61 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class InternetDialogTest extends SysuiTestCase {
 
-    private static final int SUB_ID = 1;
     private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
     private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
     private static final String WIFI_TITLE = "Connected Wi-Fi Title";
     private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary";
 
-    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
-
-    private InternetDialogFactory mInternetDialogFactory = mock(InternetDialogFactory.class);
-    private InternetAdapter mInternetAdapter = mock(InternetAdapter.class);
-    private InternetDialogController mInternetDialogController = mock(
-            InternetDialogController.class);
-    private InternetDialogController.InternetDialogCallback mCallback =
-            mock(InternetDialogController.InternetDialogCallback.class);
-    private MockInternetDialog mInternetDialog;
-    private WifiReceiver mWifiReceiver = null;
-    private WifiManager mMockWifiManager = mock(WifiManager.class);
-    private TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
-    @Mock
-    private WifiEntry mWifiEntry = mock(WifiEntry.class);
-    @Mock
-    private WifiInfo mWifiInfo;
     @Mock
     private Handler mHandler;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private WifiManager mWifiManager;
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private WifiEntry mWifiEntry;
+    @Mock
+    private InternetAdapter mInternetAdapter;
+    @Mock
+    private InternetDialogController mInternetDialogController;
+
+    private InternetDialog mInternetDialog;
+    private LinearLayout mWifiToggle;
+    private LinearLayout mConnectedWifi;
+    private RecyclerView mWifiList;
+    private LinearLayout mSeeAll;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInternetDialog = new MockInternetDialog(mContext, mInternetDialogFactory,
-                mInternetDialogController, true, true, mUiEventLogger, mHandler);
-        mInternetDialog.show();
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
-        when(mMockWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
-        mInternetDialog.setMobileNetworkTitle(MOBILE_NETWORK_TITLE);
-        mInternetDialog.setMobileNetworkSummary(MOBILE_NETWORK_SUMMARY);
-        mInternetDialog.setConnectedWifiTitle(WIFI_TITLE);
-        mInternetDialog.setConnectedWifiSummary(WIFI_SUMMARY);
-        mWifiReceiver = new WifiReceiver();
-        IntentFilter mIntentFilter = new IntentFilter();
-        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        mContext.registerReceiver(mWifiReceiver, mIntentFilter);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
+        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
         when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
         when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+
+        when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
+        when(mInternetDialogController.getMobileNetworkSummary())
+                .thenReturn(MOBILE_NETWORK_SUMMARY);
+        when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
+        when(mInternetDialogController.getInternetWifiEntry()).thenReturn(mInternetWifiEntry);
         when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
+
+        mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
+                mInternetDialogController, true, true, mock(UiEventLogger.class), mHandler);
+        mInternetDialog.mAdapter = mInternetAdapter;
+        mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
+        mInternetDialog.show();
+
+        mWifiToggle = mInternetDialog.mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mConnectedWifi = mInternetDialog.mDialogView.requireViewById(R.id.wifi_connected_layout);
+        mWifiList = mInternetDialog.mDialogView.requireViewById(R.id.wifi_list_layout);
+        mSeeAll = mInternetDialog.mDialogView.requireViewById(R.id.see_all_layout);
     }
 
     @After
@@ -136,51 +141,99 @@
     }
 
     @Test
-    public void updateDialog_withWifiOnAndHasConnectedWifi_connectedWifiLayoutVisible() {
+    public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-        when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
-        when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
-        when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
-        when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
-        mInternetDialog.updateDialog();
-        final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
-                R.id.wifi_connected_layout);
 
-        assertThat(linearLayout.getVisibility()).isEqualTo(View.VISIBLE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
     @Test
-    public void updateDialog_withWifiOnAndNoConnectedWifi_connectedWifiLayoutGone() {
+    public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
+        mInternetDialog.mConnectedWifiEntry = null;
         doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-        mInternetDialog.updateDialog();
-        final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
-                R.id.wifi_connected_layout);
 
-        assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
-    public void updateDialog_withWifiOff_WifiRecycleViewGone() {
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(false);
-        mInternetDialog.updateDialog();
-        final RecyclerView view = mInternetDialog.mDialogView.requireViewById(
-                R.id.wifi_list_layout);
+    public void updateDialog_wifiOnAndNoWifiList_hideWifiListAndSeeAll() {
+        when(mInternetDialogController.getWifiEntryList()).thenReturn(null);
 
-        assertThat(view.getVisibility()).isEqualTo(View.GONE);
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
-    public void onClickSeeMoreButton_clickSeeMore_verifyLaunchNetworkSetting() {
-        final LinearLayout seeAllLayout = mInternetDialog.mDialogView.requireViewById(
-                R.id.see_all_layout);
-        seeAllLayout.performClick();
+    public void updateDialog_wifiOnAndHasWifiList_showWifiListAndSeeAll() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasInternetWifi_showHighlightWifiToggle() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mWifiToggle.getBackground()).isNotNull();
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasInternetWifi_hideConnectedWifi() {
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasWifiList_hideWifiListAndSeeAll() {
+        // The preconditions WiFi entries are already in setUp()
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+        mInternetDialog.updateDialog();
+
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
+        mSeeAll.performClick();
 
         verify(mInternetDialogController).launchNetworkSetting();
     }
 
     @Test
     public void showProgressBar_wifiDisabled_hideProgressBar() {
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(false);
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(false);
+
+        mInternetDialog.showProgressBar();
+
+        assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+        verify(mHandler, never()).postDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showProgressBar_deviceLocked_hideProgressBar() {
+        Mockito.reset(mHandler);
+        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
 
         mInternetDialog.showProgressBar();
 
@@ -190,10 +243,11 @@
 
     @Test
     public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
         List<ScanResult> wifiScanResults = mock(ArrayList.class);
         when(wifiScanResults.size()).thenReturn(1);
-        when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
 
         mInternetDialog.showProgressBar();
 
@@ -211,10 +265,11 @@
 
     @Test
     public void showProgressBar_wifiEnabledWithoutWifiScanResults_showProgressBarThenHideSearch() {
-        when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
+        Mockito.reset(mHandler);
+        when(mWifiManager.isWifiEnabled()).thenReturn(true);
         List<ScanResult> wifiScanResults = mock(ArrayList.class);
         when(wifiScanResults.size()).thenReturn(0);
-        when(mMockWifiManager.getScanResults()).thenReturn(wifiScanResults);
+        when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
 
         mInternetDialog.showProgressBar();
 
@@ -230,78 +285,4 @@
         assertThat(mInternetDialog.mIsProgressBarVisible).isTrue();
         assertThat(mInternetDialog.mIsSearchingHidden).isTrue();
     }
-
-    private class MockInternetDialog extends InternetDialog {
-
-        private String mMobileNetworkTitle;
-        private String mMobileNetworkSummary;
-        private String mConnectedWifiTitle;
-        private String mConnectedWifiSummary;
-
-        MockInternetDialog(Context context, InternetDialogFactory internetDialogFactory,
-                InternetDialogController internetDialogController, boolean canConfigMobileData,
-                boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
-            super(context, internetDialogFactory, internetDialogController, canConfigMobileData,
-                    aboveStatusBar, uiEventLogger, handler);
-            mAdapter = mInternetAdapter;
-            mWifiManager = mMockWifiManager;
-        }
-
-        @Override
-        String getMobileNetworkTitle() {
-            return mMobileNetworkTitle;
-        }
-
-        @Override
-        String getMobileNetworkSummary() {
-            return mMobileNetworkSummary;
-        }
-
-        void setMobileNetworkTitle(String title) {
-            mMobileNetworkTitle = title;
-        }
-
-        void setMobileNetworkSummary(String summary) {
-            mMobileNetworkSummary = summary;
-        }
-
-        @Override
-        String getConnectedWifiTitle() {
-            return mConnectedWifiTitle;
-        }
-
-        @Override
-        String getConnectedWifiSummary() {
-            return mConnectedWifiSummary;
-        }
-
-        void setConnectedWifiTitle(String title) {
-            mConnectedWifiTitle = title;
-        }
-
-        void setConnectedWifiSummary(String summary) {
-            mConnectedWifiSummary = summary;
-        }
-
-        @Override
-        public void onWifiStateReceived(Context context, Intent intent) {
-            setMobileNetworkTitle(MOBILE_NETWORK_TITLE);
-            setMobileNetworkSummary(MOBILE_NETWORK_SUMMARY);
-        }
-    }
-
-    private class WifiReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
-                return;
-            }
-
-            if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                mInternetDialog.updateDialog();
-            }
-        }
-    }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 3a4bc69..670a130 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 
-import android.content.Context;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
@@ -36,7 +35,6 @@
 import android.view.ScrollCaptureResponse;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
@@ -83,7 +81,7 @@
                 /* taskId */ anyInt(), any(IScrollCaptureResponseListener.class));
 
         // Create client
-        ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm);
+        ScrollCaptureClient client = new ScrollCaptureClient(mWm, Runnable::run, mContext);
 
         // Request scroll capture
         ListenableFuture<ScrollCaptureResponse> requestFuture =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
index e0187bd..bceb928 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
@@ -108,15 +108,6 @@
     }
 
     @Test
-    fun testNullMirrorControllerNotTrackingTouch() {
-        mController.setMirrorControllerAndMirror(null)
-
-        verify(brightnessSliderView, never()).max
-        verify(brightnessSliderView, never()).value
-        verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull())
-    }
-
-    @Test
     fun testNullMirrorNotTrackingTouch() {
         whenever(mirrorController.toggleSlider).thenReturn(null)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index d23a9ce..7c045c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -184,8 +184,9 @@
     @Test
     fun setQsPanelExpansion_appliesBlur() {
         notificationShadeDepthController.qsPanelExpansion = 1f
+        notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false)
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
-        verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
+        verify(blurUtils).applyBlur(any(), eq(maxBlur / 2), eq(false))
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index 85ec3fa..f2671b76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -22,7 +22,7 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 116f807..756e984 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -41,7 +41,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
 import com.android.systemui.util.concurrency.FakeExecution
@@ -389,7 +389,6 @@
         verify(userTracker).removeCallback(userListener)
         verify(contentResolver).unregisterContentObserver(settingsObserver)
         verify(configurationController).removeCallback(configChangeListener)
-        verify(statusBarStateController).removeCallback(statusBarStateListener)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 1be14b6..8a32ce6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -64,7 +64,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 9a5482c..39d794d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -67,7 +67,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
new file mode 100644
index 0000000..24a0ad3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import static android.view.DragEvent.ACTION_DRAG_STARTED;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.DragEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
+
+    private ExpandableNotificationRow mRow;
+    private ExpandableNotificationRow mGroupRow;
+    private ExpandableNotificationRowDragController mController;
+    private NotificationTestHelper mNotificationTestHelper;
+
+    private NotificationGutsManager mGutsManager = mock(NotificationGutsManager.class);
+    private HeadsUpManager mHeadsUpManager = mock(HeadsUpManager.class);
+    private NotificationMenuRow mMenuRow = mock(NotificationMenuRow.class);
+    private NotificationMenuRowPlugin.MenuItem mMenuItem =
+            mock(NotificationMenuRowPlugin.MenuItem.class);
+
+    @Before
+    public void setUp() throws Exception {
+        allowTestableLooperAsMainThread();
+
+        mDependency.injectMockDependency(ShadeController.class);
+
+        mNotificationTestHelper = new NotificationTestHelper(
+                mContext,
+                mDependency,
+                TestableLooper.get(this));
+        mRow = mNotificationTestHelper.createRow();
+        mGroupRow = mNotificationTestHelper.createGroup(4);
+        when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
+
+        mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager);
+    }
+
+    @Test
+    public void testDoStartDragHeadsUpNotif_startDragAndDrop() throws Exception {
+        ExpandableNotificationRowDragController controller = createSpyController();
+        mRow.setDragController(controller);
+        mRow.setHeadsUp(true);
+        mRow.setPinned(true);
+
+        mRow.doLongClickCallback(0, 0);
+        mRow.doDragCallback(0, 0);
+        verify(controller).startDragAndDrop(mRow);
+
+        // Simulate the drag start
+        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
+                null, null, false));
+        verify(mHeadsUpManager, times(1)).releaseAllImmediately();
+    }
+
+    @Test
+    public void testDoStartDragNotif() throws Exception {
+        ExpandableNotificationRowDragController controller = createSpyController();
+        mRow.setDragController(controller);
+
+        mDependency.get(ShadeController.class).instantExpandNotificationsPanel();
+        mRow.doDragCallback(0, 0);
+        verify(controller).startDragAndDrop(mRow);
+
+        // Simulate the drag start
+        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
+                null, null, false));
+        verify(mDependency.get(ShadeController.class)).animateCollapsePanels(0, true);
+    }
+
+    private ExpandableNotificationRowDragController createSpyController() {
+        return spy(mController);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index cea49b7..4562e4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -47,11 +47,11 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -265,7 +265,8 @@
                                 new FalsingManagerFake(),
                                 new FalsingCollectorFake(),
                                 mPeopleNotificationIdentifier,
-                                Optional.of(mock(BubblesManager.class))
+                                Optional.of(mock(BubblesManager.class)),
+                                mock(ExpandableNotificationRowDragController.class)
                         ));
 
         when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index c56d085..07ebaea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -46,11 +46,11 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d02d77e..4e76b16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -52,7 +52,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationShelfController;
 import com.android.systemui.statusbar.StatusBarState;
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 f10565c..55c69f7 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
@@ -37,9 +37,9 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 5bf1bb3..7a0b366 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -38,7 +38,7 @@
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
 import com.android.systemui.doze.DozeScreenState;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.tuner.TunerService;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 6e0cbd9..bca1227 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -202,6 +202,5 @@
         verify(mPanelView).removeTrackingHeadsUpListener(any());
         verify(mPanelView).setHeadsUpAppearanceController(isNull());
         verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
-        verify(mStackScrollerController).removeOnLayoutChangeListener(any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 690b841..2e76bd7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -38,35 +38,27 @@
     private static final float ZERO_DRAG = 0.f;
     private static final float OPAQUE = 1.f;
     private static final float TRANSPARENT = 0.f;
-    private static final boolean HAS_CUSTOM_CLOCK = false;
-    private static final boolean HAS_VISIBLE_NOTIFS = false;
 
     private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
     private KeyguardClockPositionAlgorithm.Result mClockPosition;
-    private int mNotificationStackHeight;
     private float mPanelExpansion;
     private int mKeyguardStatusHeight;
     private float mDark;
-    private boolean mHasCustomClock;
-    private boolean mHasVisibleNotifs;
     private float mQsExpansion;
-    private int mCutoutTopInset = 0; // in pixels
+    private int mCutoutTopInsetPx = 0;
+    private int mSplitShadeSmartspaceHeightPx = 0;
     private boolean mIsSplitShade = false;
 
     @Before
     public void setUp() {
         mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
         mClockPosition = new KeyguardClockPositionAlgorithm.Result();
-
-        mHasCustomClock = HAS_CUSTOM_CLOCK;
-        mHasVisibleNotifs = HAS_VISIBLE_NOTIFS;
     }
 
     @Test
     public void clockPositionTopOfScreenOnAOD() {
-        // GIVEN on AOD and both stack scroll and clock have 0 height
+        // GIVEN on AOD and clock has 0 height
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         // WHEN the clock position algorithm is run
         positionClock();
@@ -79,11 +71,10 @@
 
     @Test
     public void clockPositionBelowCutout() {
-        // GIVEN on AOD and both stack scroll and clock have 0 height
+        // GIVEN on AOD and clock has 0 height
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
-        mCutoutTopInset = 300;
+        mCutoutTopInsetPx = 300;
         // WHEN the clock position algorithm is run
         positionClock();
         // THEN the clock Y position is below the cutout
@@ -97,7 +88,6 @@
     public void clockPositionAdjustsForKeyguardStatusOnAOD() {
         // GIVEN on AOD with a clock of height 100
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = 100;
         // WHEN the clock position algorithm is run
         positionClock();
@@ -112,7 +102,6 @@
     public void clockPositionLargeClockOnAOD() {
         // GIVEN on AOD with a full screen clock
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = SCREEN_HEIGHT;
         // WHEN the clock position algorithm is run
         positionClock();
@@ -125,9 +114,8 @@
 
     @Test
     public void clockPositionTopOfScreenOnLockScreen() {
-        // GIVEN on lock screen with stack scroll and clock of 0 height
+        // GIVEN on lock screen with clock of 0 height
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         // WHEN the clock position algorithm is run
         positionClock();
@@ -138,24 +126,9 @@
     }
 
     @Test
-    public void clockPositionWithStackScrollExpandOnLockScreen() {
-        // GIVEN on lock screen with stack scroll of height 500
-        givenLockScreen();
-        mNotificationStackHeight = 500;
-        mKeyguardStatusHeight = EMPTY_HEIGHT;
-        // WHEN the clock position algorithm is run
-        positionClock();
-        // THEN the clock Y position stays to the top
-        assertThat(mClockPosition.clockY).isEqualTo(0);
-        // AND the clock is positioned on the left.
-        assertThat(mClockPosition.clockX).isEqualTo(0);
-    }
-
-    @Test
     public void clockPositionWithPartialDragOnLockScreen() {
         // GIVEN dragging up on lock screen
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         mPanelExpansion = 0.5f;
         // WHEN the clock position algorithm is run
@@ -171,7 +144,6 @@
     public void clockPositionWithFullDragOnLockScreen() {
         // GIVEN the lock screen is dragged up
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         mPanelExpansion = 0.f;
         // WHEN the clock position algorithm is run
@@ -184,7 +156,6 @@
     public void largeClockOnLockScreenIsTransparent() {
         // GIVEN on lock screen with a full screen clock
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = SCREEN_HEIGHT;
         // WHEN the clock position algorithm is run
         positionClock();
@@ -194,9 +165,8 @@
 
     @Test
     public void notifPositionTopOfScreenOnAOD() {
-        // GIVEN on AOD and both stack scroll and clock have 0 height
+        // GIVEN on AOD and clock has 0 height
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         // WHEN the position algorithm is run
         positionClock();
@@ -208,7 +178,6 @@
     public void notifPositionIndependentOfKeyguardStatusHeightOnAOD() {
         // GIVEN on AOD and clock has a nonzero height
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = 100;
         // WHEN the position algorithm is run
         positionClock();
@@ -220,7 +189,6 @@
     public void notifPositionWithLargeClockOnAOD() {
         // GIVEN on AOD and clock has a nonzero height
         givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = SCREEN_HEIGHT;
         // WHEN the position algorithm is run
         positionClock();
@@ -230,9 +198,8 @@
 
     @Test
     public void notifPositionMiddleOfScreenOnLockScreen() {
-        // GIVEN on lock screen and both stack scroll and clock have 0 height
+        // GIVEN on lock screen and clock has 0 height
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         // WHEN the position algorithm is run
         positionClock();
@@ -241,47 +208,21 @@
     }
 
     @Test
-    public void notifPositionAdjustsForStackHeightOnLockScreen() {
-        // GIVEN on lock screen and stack scroller has a nonzero height
-        givenLockScreen();
-        mNotificationStackHeight = 500;
-        mKeyguardStatusHeight = EMPTY_HEIGHT;
-        // WHEN the position algorithm is run
-        positionClock();
-        // THEN the notif padding adjusts for keyguard status height
-        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
-    }
-
-    @Test
     public void notifPositionAdjustsForClockHeightOnLockScreen() {
         // GIVEN on lock screen and stack scroller has a nonzero height
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = 200;
         // WHEN the position algorithm is run
         positionClock();
-        // THEN the notif padding adjusts for both clock and notif stack.
-        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
-    }
 
-    @Test
-    public void notifPositionAdjustsForStackHeightAndClockHeightOnLockScreen() {
-        // GIVEN on lock screen and stack scroller has a nonzero height
-        givenLockScreen();
-        mNotificationStackHeight = 500;
-        mKeyguardStatusHeight = 200;
-        // WHEN the position algorithm is run
-        positionClock();
-        // THEN the notifs are placed below the statusview
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
     }
 
     @Test
     public void notifPositionAlignedWithClockInSplitShadeMode() {
-        // GIVEN on lock screen and split shade mode
         givenLockScreen();
         mIsSplitShade = true;
-        mHasCustomClock = true;
+        mKeyguardStatusHeight = 200;
         // WHEN the position algorithm is run
         positionClock();
         // THEN the notif padding DOESN'T adjust for keyguard status height.
@@ -289,10 +230,20 @@
     }
 
     @Test
+    public void notifPositionAdjustedBySmartspaceHeightInSplitShadeMode() {
+        givenLockScreen();
+        mSplitShadeSmartspaceHeightPx = 200;
+        mIsSplitShade = true;
+        // WHEN the position algorithm is run
+        positionClock();
+
+        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
+    }
+
+    @Test
     public void notifPositionWithLargeClockOnLockScreen() {
         // GIVEN on lock screen and clock has a nonzero height
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = SCREEN_HEIGHT;
         // WHEN the position algorithm is run
         positionClock();
@@ -304,7 +255,6 @@
     public void notifPositionWithFullDragOnLockScreen() {
         // GIVEN the lock screen is dragged up
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = EMPTY_HEIGHT;
         mPanelExpansion = 0.f;
         // WHEN the clock position algorithm is run
@@ -317,19 +267,18 @@
     public void notifPositionWithLargeClockFullDragOnLockScreen() {
         // GIVEN the lock screen is dragged up and a full screen clock
         givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
         mKeyguardStatusHeight = SCREEN_HEIGHT;
         mPanelExpansion = 0.f;
         // WHEN the clock position algorithm is run
         positionClock();
-        // THEN the notif padding is zero.
+
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(
                 (int) (mKeyguardStatusHeight * .667f));
     }
 
     @Test
     public void clockHiddenWhenQsIsExpanded() {
-        // GIVEN on the lock screen with a custom clock and visible notifications
+        // GIVEN on the lock screen with visible notifications
         givenLockScreen();
         mQsExpansion = 1;
         // WHEN the clock position algorithm is run
@@ -349,12 +298,12 @@
     }
 
     private void positionClock() {
-        mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
-                mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight,
+        mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT,
+                mPanelExpansion, mKeyguardStatusHeight,
                 0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
-                mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
+                mDark, ZERO_DRAG, false /* bypassEnabled */,
                 0 /* unlockedStackScrollerPadding */, mQsExpansion,
-                mCutoutTopInset, mIsSplitShade);
+                mCutoutTopInsetPx, mSplitShadeSmartspaceHeightPx, mIsSplitShade);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 217a77d..9cc762c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -28,7 +28,8 @@
 import com.android.keyguard.CarrierTextController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -59,6 +60,8 @@
     private StatusBarIconController mStatusBarIconController;
     @Mock
     private FeatureFlags mFeatureFlags;
+    @Mock
+    private BatteryMeterViewController mBatteryMeterViewController;
 
     private KeyguardStatusBarViewController mController;
 
@@ -78,7 +81,8 @@
                 mBatteryController,
                 mUserInfoController,
                 mStatusBarIconController,
-                new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags)
+                new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
+                mBatteryMeterViewController
         );
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index c54607f..11a822c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -63,6 +63,7 @@
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
@@ -93,9 +94,12 @@
 import com.android.systemui.communal.CommunalSource;
 import com.android.systemui.communal.CommunalSourceMonitor;
 import com.android.systemui.communal.dagger.CommunalViewComponent;
+import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.idle.IdleHostViewController;
+import com.android.systemui.idle.dagger.IdleViewComponent;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
@@ -116,6 +120,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -244,6 +249,12 @@
     @Mock
     private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
     @Mock
+    private IdleViewComponent.Factory mIdleViewComponentFactory;
+    @Mock
+    private IdleViewComponent mIdleViewComponent;
+    @Mock
+    private IdleHostViewController mIdleHostViewController;
+    @Mock
     private QSDetailDisplayer mQSDetailDisplayer;
     @Mock
     private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
@@ -315,6 +326,12 @@
     private NotificationRemoteInputManager mNotificationRemoteInputManager;
     @Mock
     private RecordingController mRecordingController;
+    @Mock
+    private ControlsComponent mControlsComponent;
+    @Mock
+    private LockscreenSmartspaceController mLockscreenSmartspaceController;
+    @Mock
+    private FrameLayout mSplitShadeSmartspaceContainer;
 
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
@@ -365,6 +382,8 @@
         when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
         when(mView.findViewById(R.id.keyguard_status_view))
                 .thenReturn(mock(KeyguardStatusView.class));
+        when(mView.findViewById(R.id.split_shade_smartspace_container))
+                .thenReturn(mSplitShadeSmartspaceContainer);
         mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
         mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
         mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
@@ -413,6 +432,10 @@
                 .thenReturn(mCommunalViewComponent);
         when(mCommunalViewComponent.getCommunalHostViewController())
                 .thenReturn(mCommunalHostViewController);
+        when(mIdleViewComponentFactory.build(any()))
+                .thenReturn(mIdleViewComponent);
+        when(mIdleViewComponent.getIdleHostViewController())
+                .thenReturn(mIdleHostViewController);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
                 .thenReturn(mKeyguardStatusView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
@@ -441,6 +464,7 @@
                 mKeyguardUserSwitcherComponentFactory,
                 mKeyguardStatusBarViewComponentFactory,
                 mCommunalViewComponentFactory,
+                mIdleViewComponentFactory,
                 mLockscreenShadeTransitionController,
                 mQSDetailDisplayer,
                 mGroupManager,
@@ -463,8 +487,10 @@
                 new FakeExecutor(new FakeSystemClock()),
                 mSecureSettings,
                 mSplitShadeHeaderController,
+                mLockscreenSmartspaceController,
                 mUnlockedScreenOffAnimationController,
-                mNotificationRemoteInputManager);
+                mNotificationRemoteInputManager,
+                mControlsComponent);
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
                 mNotificationShelfController);
@@ -821,6 +847,13 @@
     }
 
     @Test
+    public void testCommunalhostViewControllerInit() {
+        clearInvocations(mCommunalHostViewController);
+        givenViewAttached();
+        verify(mCommunalHostViewController).init();
+    }
+
+    @Test
     public void testCommunalSourceListening() {
         final ArgumentCaptor<CommunalSourceMonitor.Callback> monitorCallback =
                 ArgumentCaptor.forClass(CommunalSourceMonitor.Callback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
new file mode 100644
index 0000000..50cea07
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class PhoneStatusBarViewControllerTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var commandQueue: CommandQueue
+
+    private lateinit var view: PhoneStatusBarView
+    private lateinit var controller: PhoneStatusBarViewController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        view = PhoneStatusBarView(mContext, null)
+        controller = PhoneStatusBarViewController(view, commandQueue)
+    }
+
+    @Test
+    fun constructor_setsPanelEnabledProviderOnView() {
+        var providerUsed = false
+        `when`(commandQueue.panelsEnabled()).then {
+            providerUsed = true
+            true
+        }
+
+        // If the constructor correctly set a [PanelEnabledProvider], then it should be used
+        // when [PhoneStatusBarView.panelEnabled] is called.
+        view.panelEnabled()
+
+        assertThat(providerUsed).isTrue()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
new file mode 100644
index 0000000..49ab6eb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class PhoneStatusBarViewTest : SysuiTestCase() {
+
+    private lateinit var view: PhoneStatusBarView
+
+    @Before
+    fun setUp() {
+        view = PhoneStatusBarView(mContext, null)
+    }
+
+    @Test
+    fun panelEnabled_providerReturnsTrue_returnsTrue() {
+        view.setPanelEnabledProvider { true }
+
+        assertThat(view.panelEnabled()).isTrue()
+    }
+
+    @Test
+    fun panelEnabled_providerReturnsFalse_returnsFalse() {
+        view.setPanelEnabledProvider { false }
+
+        assertThat(view.panelEnabled()).isFalse()
+    }
+
+    @Test
+    fun panelEnabled_noProvider_noCrash() {
+        view.panelEnabled()
+        // No assert needed, just testing no crash
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 2685b76..30fc13b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -83,7 +83,6 @@
     private ScrimView mScrimBehind;
     private ScrimView mNotificationsScrim;
     private ScrimView mScrimInFront;
-    private ScrimView mScrimForBubble;
     private ScrimState mScrimState;
     private float mScrimBehindAlpha;
     private GradientColors mScrimInFrontColor;
@@ -167,7 +166,6 @@
         endAnimation(mNotificationsScrim);
         endAnimation(mScrimBehind);
         endAnimation(mScrimInFront);
-        endAnimation(mScrimForBubble);
 
         assertEquals("Animators did not finish",
                 mAnimatorListener.getNumStarts(), mAnimatorListener.getNumEnds());
@@ -190,7 +188,6 @@
 
         mScrimBehind = spy(new ScrimView(getContext()));
         mScrimInFront = new ScrimView(getContext());
-        mScrimForBubble = new ScrimView(getContext());
         mNotificationsScrim = new ScrimView(getContext());
         mAlwaysOnEnabled = true;
         mLooper = TestableLooper.get(this);
@@ -226,8 +223,7 @@
                 mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
                 mUnlockedScreenOffAnimationController);
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
-        mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront,
-                mScrimForBubble);
+        mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
 
         mScrimController.setHasBackdrop(false);
@@ -257,8 +253,8 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false));
+                mScrimBehind, true
+        ));
     }
 
     @Test
@@ -274,8 +270,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -293,8 +288,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -309,8 +303,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
 
         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
@@ -329,8 +322,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -369,8 +361,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -389,8 +380,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -510,8 +500,7 @@
 
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
 
         // ... and when ambient goes dark, front scrim should be semi-transparent
@@ -549,8 +538,7 @@
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
                 mScrimBehind, false,
-                mNotificationsScrim, false,
-                mScrimForBubble, false
+                mNotificationsScrim, false
         ));
     }
 
@@ -570,8 +558,7 @@
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
                 mScrimBehind, true,
-                mNotificationsScrim, false,
-                mScrimForBubble, false
+                mNotificationsScrim, false
         ));
     }
 
@@ -627,8 +614,7 @@
                 mScrimBehind, TRANSPARENT));
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
-                mScrimBehind, false,
-                mScrimForBubble, false
+                mScrimBehind, false
         ));
     }
 
@@ -645,8 +631,7 @@
         assertScrimTinted(Map.of(
                 mNotificationsScrim, false,
                 mScrimInFront, false,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
 
         // Back scrim should be visible after start dragging
@@ -657,27 +642,6 @@
                 mScrimBehind, SEMI_TRANSPARENT));
     }
 
-    @Test
-    public void transitionToBubbleExpanded() {
-        mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
-        finishAnimationsImmediately();
-
-        assertScrimTinted(Map.of(
-                mScrimInFront, false,
-                mScrimBehind, false,
-                mScrimForBubble, true
-        ));
-
-        // Front scrim should be transparent
-        assertEquals(ScrimController.TRANSPARENT,
-                mScrimInFront.getViewAlpha(), 0.0f);
-        // Back scrim should be visible
-        assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
-                mScrimBehind.getViewAlpha(), 0.0f);
-        // Bubble scrim should be visible
-        assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA,
-                mScrimForBubble.getViewAlpha(), 0.0f);
-    }
 
     @Test
     public void scrimStateCallback() {
@@ -787,8 +751,7 @@
         // Immediately tinted black after the transition starts
         assertScrimTinted(Map.of(
                 mScrimInFront, true,
-                mScrimBehind, true,
-                mScrimForBubble, true
+                mScrimBehind, true
         ));
 
         finishAnimationsImmediately();
@@ -796,14 +759,12 @@
         // All scrims should be transparent at the end of fade transition.
         assertScrimAlpha(Map.of(
                 mScrimInFront, TRANSPARENT,
-                mScrimBehind, TRANSPARENT,
-                mScrimForBubble, TRANSPARENT));
+                mScrimBehind, TRANSPARENT));
 
         // Make sure at the very end of the animation, we're reset to transparent
         assertScrimTinted(Map.of(
                 mScrimInFront, false,
-                mScrimBehind, true,
-                mScrimForBubble, false
+                mScrimBehind, true
         ));
     }
 
@@ -821,8 +782,7 @@
                                 + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0);
                         assertScrimTinted(Map.of(
                                 mScrimInFront, true,
-                                mScrimBehind, true,
-                                mScrimForBubble, true
+                                mScrimBehind, true
                         ));
                         Assert.assertSame("Scrim should be visible during transition.",
                                 mScrimVisibility, OPAQUE);
@@ -1075,8 +1035,6 @@
                 mScrimInFront.getDefaultFocusHighlightEnabled());
         Assert.assertFalse("Scrim shouldn't have focus highlight",
                 mScrimBehind.getDefaultFocusHighlightEnabled());
-        Assert.assertFalse("Scrim shouldn't have focus highlight",
-                mScrimForBubble.getDefaultFocusHighlightEnabled());
     }
 
     @Test
@@ -1086,7 +1044,7 @@
         HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
                 ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
                 ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
-                ScrimState.BUBBLE_EXPANDED, ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
+                ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
 
         for (ScrimState state : ScrimState.values()) {
             if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
@@ -1239,21 +1197,16 @@
             return "behind";
         } else if (scrim == mNotificationsScrim) {
             return "notifications";
-        } else if (scrim == mScrimForBubble) {
-            return "bubble";
         }
         return "unknown_scrim";
     }
 
     /**
-     * If {@link #mScrimForBubble} or {@link #mNotificationsScrim} is not passed in the map
+     * If {@link #mNotificationsScrim} is not passed in the map
      * we assume it must be transparent
      */
     private void assertScrimAlpha(Map<ScrimView, Integer> scrimToAlpha) {
         // Check single scrim visibility.
-        if (!scrimToAlpha.containsKey(mScrimForBubble)) {
-            assertScrimAlpha(mScrimForBubble, TRANSPARENT);
-        }
         if (!scrimToAlpha.containsKey(mNotificationsScrim)) {
             assertScrimAlpha(mNotificationsScrim, TRANSPARENT);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
new file mode 100644
index 0000000..52538c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.StatusBarManager;
+import android.os.PowerManager;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase {
+    @Mock private StatusBar mStatusBar;
+    @Mock private ShadeController mShadeController;
+    @Mock private CommandQueue mCommandQueue;
+    @Mock private NotificationPanelViewController mNotificationPanelViewController;
+    @Mock private LegacySplitScreen mLegacySplitScreen;
+    @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+    private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private AssistManager mAssistManager;
+    @Mock private DozeServiceHost mDozeServiceHost;
+    @Mock private StatusBarStateControllerImpl mStatusBarStateController;
+    @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
+    @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+    @Mock private PowerManager mPowerManager;
+    @Mock private VibratorHelper mVibratorHelper;
+    @Mock private Vibrator mVibrator;
+    @Mock private LightBarController mLightBarController;
+
+    StatusBarCommandQueueCallbacks mSbcqCallbacks;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        mSbcqCallbacks = new StatusBarCommandQueueCallbacks(
+                mStatusBar,
+                mContext,
+                mContext.getResources(),
+                mShadeController,
+                mCommandQueue,
+                mNotificationPanelViewController,
+                Optional.of(mLegacySplitScreen),
+                mRemoteInputQuickSettingsDisabler,
+                mMetricsLogger,
+                mKeyguardUpdateMonitor,
+                mKeyguardStateController,
+                mHeadsUpManager,
+                mWakefulnessLifecycle,
+                mDeviceProvisionedController,
+                mStatusBarKeyguardViewManager,
+                mAssistManager,
+                mDozeServiceHost,
+                mStatusBarStateController,
+                mNotificationShadeWindowView,
+                mNotificationStackScrollLayoutController,
+                mPowerManager,
+                mVibratorHelper,
+                Optional.of(mVibrator),
+                mLightBarController,
+                DEFAULT_DISPLAY);
+
+        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+        when(mRemoteInputQuickSettingsDisabler.adjustDisableFlags(anyInt()))
+                .thenAnswer((Answer<Integer>) invocation -> invocation.getArgument(0));
+    }
+
+    @Test
+    public void testDisableNotificationShade() {
+        when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+        when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE_NONE);
+        when(mCommandQueue.panelsEnabled()).thenReturn(false);
+        mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+                StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
+
+        verify(mStatusBar).updateQsExpansionEnabled();
+        verify(mShadeController).animateCollapsePanels();
+
+        // Trying to open it does nothing.
+        mSbcqCallbacks.animateExpandNotificationsPanel();
+        verify(mNotificationPanelViewController, never()).expandWithoutQs();
+        mSbcqCallbacks.animateExpandSettingsPanel(null);
+        verify(mNotificationPanelViewController, never()).expand(anyBoolean());
+    }
+
+    @Test
+    public void testEnableNotificationShade() {
+        when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+        when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE2_NOTIFICATION_SHADE);
+        when(mCommandQueue.panelsEnabled()).thenReturn(true);
+        mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+                StatusBarManager.DISABLE2_NONE, false);
+        verify(mStatusBar).updateQsExpansionEnabled();
+        verify(mShadeController, never()).animateCollapsePanels();
+
+        // Can now be opened.
+        mSbcqCallbacks.animateExpandNotificationsPanel();
+        verify(mNotificationPanelViewController).expandWithoutQs();
+        mSbcqCallbacks.animateExpandSettingsPanel(null);
+        verify(mNotificationPanelViewController).expandWithQs();
+    }
+
+    @Test
+    public void testSuppressAmbientDisplay_suppress() {
+        mSbcqCallbacks.suppressAmbientDisplay(true);
+        verify(mDozeServiceHost).setDozeSuppressed(true);
+    }
+
+    @Test
+    public void testSuppressAmbientDisplay_unsuppress() {
+        mSbcqCallbacks.suppressAmbientDisplay(false);
+        verify(mDozeServiceHost).setDozeSuppressed(false);
+    }
+
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index e3263d4..0f1c40b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -30,8 +30,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 83bf96b..72a3d66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -53,10 +53,10 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationClickNotifier;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 2a58f7c..e4f6e13d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -18,7 +18,6 @@
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.view.Display.DEFAULT_DISPLAY;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -40,7 +39,7 @@
 
 import android.app.IWallpaperManager;
 import android.app.Notification;
-import android.app.StatusBarManager;
+import android.app.WallpaperManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -78,29 +77,25 @@
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.settings.brightness.BrightnessSlider;
 import com.android.systemui.shared.plugins.PluginManager;
-import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationListener;
@@ -114,11 +109,8 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -143,14 +135,15 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.startingsurface.StartingSurface;
@@ -181,7 +174,6 @@
 
     @Mock private NotificationsController mNotificationsController;
     @Mock private LightBarController mLightBarController;
-    @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private KeyguardStateController mKeyguardStateController;
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
@@ -206,7 +198,6 @@
     @Mock private BatteryController mBatteryController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarNotificationPresenter mNotificationPresenter;
-    @Mock private NotificationEntryListener mEntryListener;
     @Mock private NotificationFilter mNotificationFilter;
     @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@@ -217,7 +208,6 @@
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NavigationBarController mNavigationBarController;
-    @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
     @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier;
     @Mock private SysuiColorExtractor mColorExtractor;
     @Mock private ColorExtractor.GradientColors mGradientColors;
@@ -229,7 +219,6 @@
     @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
     @Mock private UserSwitcherController mUserSwitcherController;
     @Mock private NetworkController mNetworkController;
-    @Mock private VibratorHelper mVibratorHelper;
     @Mock private BubblesManager mBubblesManager;
     @Mock private Bubbles mBubbles;
     @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -240,7 +229,6 @@
     @Mock private LockscreenWallpaper mLockscreenWallpaper;
     @Mock private DozeServiceHost mDozeServiceHost;
     @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
-    @Mock private KeyguardLiftController mKeyguardLiftController;
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
     @Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
@@ -251,12 +239,10 @@
     @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     @Mock private LightsOutNotifController mLightsOutNotifController;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
-    @Mock private DismissCallbackRegistry mDismissCallbackRegistry;
     @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     @Mock private ScreenPinningRequest mScreenPinningRequest;
     @Mock private StatusBarNotificationActivityStarter.Builder
             mStatusBarNotificationActivityStarterBuilder;
-    @Mock private DarkIconDispatcher mDarkIconDispatcher;
     @Mock private PluginDependencyProvider mPluginDependencyProvider;
     @Mock private KeyguardDismissUtil mKeyguardDismissUtil;
     @Mock private ExtensionController mExtensionController;
@@ -265,7 +251,6 @@
     @Mock private DemoModeController mDemoModeController;
     @Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
     @Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
-    @Mock private WiredChargingRippleController mWiredChargingRippleController;
     @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
     @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
     @Mock private OngoingCallController mOngoingCallController;
@@ -274,9 +259,11 @@
     @Mock private StatusBarIconController mIconController;
     @Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
     @Mock private FeatureFlags mFeatureFlags;
-    @Mock private IWallpaperManager mWallpaperManager;
+    @Mock private WallpaperManager mWallpaperManager;
+    @Mock private IWallpaperManager mIWallpaperManager;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private TunerService mTunerService;
     @Mock private StartingSurface mStartingSurface;
     private ShadeController mShadeController;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -335,7 +322,7 @@
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
         WakefulnessLifecycle wakefulnessLifecycle =
-                new WakefulnessLifecycle(mContext, mWallpaperManager);
+                new WakefulnessLifecycle(mContext, mIWallpaperManager);
         wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
         wakefulnessLifecycle.dispatchFinishedWakingUp();
 
@@ -362,7 +349,6 @@
                 mLightBarController,
                 mAutoHideController,
                 mKeyguardUpdateMonitor,
-                mStatusBarSignalPolicy,
                 mPulseExpansionHandler,
                 mNotificationWakeUpCoordinator,
                 mKeyguardBypassController,
@@ -373,11 +359,6 @@
                 new FalsingManagerFake(),
                 new FalsingCollectorFake(),
                 mBroadcastDispatcher,
-                new RemoteInputQuickSettingsDisabler(
-                        mContext,
-                        configurationController,
-                        mCommandQueue
-                ),
                 mNotificationGutsManager,
                 notificationLogger,
                 mNotificationInterruptStateProvider,
@@ -396,19 +377,16 @@
                 new ScreenLifecycle(),
                 wakefulnessLifecycle,
                 mStatusBarStateController,
-                mVibratorHelper,
                 Optional.of(mBubblesManager),
                 Optional.of(mBubbles),
                 mVisualStabilityManager,
                 mDeviceProvisionedController,
                 mNavigationBarController,
-                mAccessibilityFloatingMenuController,
                 () -> mAssistManager,
                 configurationController,
                 mNotificationShadeWindowController,
                 mDozeParameters,
                 mScrimController,
-                mKeyguardLiftController,
                 mLockscreenWallpaperLazy,
                 mBiometricUnlockControllerLazy,
                 mDozeServiceHost,
@@ -433,13 +411,11 @@
                 mUserInfoControllerImpl,
                 mPhoneStatusBarPolicy,
                 mKeyguardIndicationController,
-                mDismissCallbackRegistry,
                 mDemoModeController,
                 mNotificationShadeDepthControllerLazy,
                 mStatusBarTouchableRegionManager,
                 mNotificationIconAreaController,
                 mBrightnessSliderFactory,
-                mWiredChargingRippleController,
                 mUnfoldTransitionConfig,
                 mUnfoldLightRevealOverlayAnimationLazy,
                 mOngoingCallController,
@@ -449,8 +425,10 @@
                 mLockscreenTransitionController,
                 mFeatureFlags,
                 mKeyguardUnlockAnimationController,
+                mWallpaperManager,
                 mUnlockedScreenOffAnimationController,
-                Optional.of(mStartingSurface));
+                Optional.of(mStartingSurface),
+                mTunerService);
         when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
                 any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
                 any(ViewGroup.class), any(KeyguardBypassController.class)))
@@ -754,31 +732,6 @@
     }
 
     @Test
-    public void testDisableExpandStatusBar() {
-        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
-        mStatusBar.setUserSetupForTest(true);
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-
-        when(mCommandQueue.panelsEnabled()).thenReturn(false);
-        mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
-                StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
-        verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(false);
-        mStatusBar.animateExpandNotificationsPanel();
-        verify(mNotificationPanelViewController, never()).expand(anyBoolean());
-        mStatusBar.animateExpandSettingsPanel(null);
-        verify(mNotificationPanelViewController, never()).expand(anyBoolean());
-
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
-                StatusBarManager.DISABLE2_NONE, false);
-        verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(true);
-        mStatusBar.animateExpandNotificationsPanel();
-        verify(mNotificationPanelViewController).expandWithoutQs();
-        mStatusBar.animateExpandSettingsPanel(null);
-        verify(mNotificationPanelViewController).expandWithQs();
-    }
-
-    @Test
     public void testDump_DoesNotCrash() {
         mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null);
     }
@@ -905,18 +858,6 @@
     }
 
     @Test
-    public void testSuppressAmbientDisplay_suppress() {
-        mStatusBar.suppressAmbientDisplay(true);
-        verify(mDozeServiceHost).setDozeSuppressed(true);
-    }
-
-    @Test
-    public void testSuppressAmbientDisplay_unsuppress() {
-        mStatusBar.suppressAmbientDisplay(false);
-        verify(mDozeServiceHost).setDozeSuppressed(false);
-    }
-
-    @Test
     public void testUpdateResources_updatesBouncer() {
         mStatusBar.updateResources();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index d36cb0b..4476fd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -34,7 +34,7 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -184,6 +184,21 @@
                 .isGreaterThan(0)
     }
 
+    /** Regression test for b/194731244. */
+    @Test
+    fun onEntryUpdated_calledManyTimes_uidObserverUnregisteredManyTimes() {
+        val numCalls = 4
+
+        for (i in 0 until numCalls) {
+            // Re-create the notification each time so that it's considered a different object and
+            // observers will get re-registered (and hopefully unregistered).
+            notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+        }
+
+        // There should be 1 observer still registered, so we should unregister n-1 times.
+        verify(mockIActivityManager, times(numCalls - 1)).unregisterUidObserver(any())
+    }
+
     /**
      * If a call notification is never added before #onEntryRemoved is called, then the listener
      * should never be notified.
@@ -223,7 +238,6 @@
         verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
     }
 
-
     @Test
     fun onEntryRemoved_notifKeyDoesNotMatchOngoingCallNotif_listenerNotNotified() {
         notifCollectionListener.onEntryAdded(createOngoingCallNotifEntry())
@@ -349,7 +363,7 @@
         // Update the process to visible.
         uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_VISIBLE, 0, 0)
         mainExecutor.advanceClockToLast()
-        mainExecutor.runAllReady();
+        mainExecutor.runAllReady()
 
         verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
     }
@@ -370,7 +384,7 @@
         // Update the process to invisible.
         uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_INVISIBLE, 0, 0)
         mainExecutor.advanceClockToLast()
-        mainExecutor.runAllReady();
+        mainExecutor.runAllReady()
 
         verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
new file mode 100644
index 0000000..30717f4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
+
+    private static final String[] DEFAULT_SETTINGS = new String[]{
+            "0:0",
+            "1:2"
+    };
+
+    private final FakeSettings mFakeSettings = new FakeSettings();
+    private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+    private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
+    @Mock DeviceStateManager mDeviceStateManager;
+    RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
+    DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+    private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(/* testClass= */ this);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+
+        ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(
+                        DeviceStateManager.DeviceStateCallback.class);
+
+        mDeviceStateRotationLockSettingController = new DeviceStateRotationLockSettingController(
+                mFakeSettings,
+                mFakeRotationPolicy,
+                mDeviceStateManager,
+                mFakeExecutor,
+                DEFAULT_SETTINGS
+        );
+
+        mDeviceStateRotationLockSettingController.setListening(true);
+        verify(mDeviceStateManager).registerCallback(any(),
+                deviceStateCallbackArgumentCaptor.capture());
+        mDeviceStateCallback = deviceStateCallbackArgumentCaptor.getValue();
+    }
+
+    @Test
+    public void whenSavedSettingsEmpty_defaultsLoadedAndSaved() {
+        mFakeSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK, "",
+                UserHandle.USER_CURRENT);
+
+        mDeviceStateRotationLockSettingController.initialize();
+
+        assertThat(mFakeSettings
+                .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                        UserHandle.USER_CURRENT))
+                .isEqualTo("0:0:1:2");
+    }
+
+    @Test
+    public void whenNoSavedValueForDeviceState_assumeIgnored() {
+        mFakeSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                /* value= */"0:2:1:2",
+                UserHandle.USER_CURRENT);
+        mFakeRotationPolicy.setRotationLock(true);
+        mDeviceStateRotationLockSettingController.initialize();
+
+        mDeviceStateCallback.onStateChanged(1);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+        // Settings only exist for state 0 and 1
+        mDeviceStateCallback.onStateChanged(2);
+
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+    }
+
+    @Test
+    public void whenDeviceStateSwitched_loadCorrectSetting() {
+        mFakeSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                /* value= */"0:2:1:1",
+                UserHandle.USER_CURRENT);
+        mFakeRotationPolicy.setRotationLock(true);
+        mDeviceStateRotationLockSettingController.initialize();
+
+        mDeviceStateCallback.onStateChanged(0);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+        mDeviceStateCallback.onStateChanged(1);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+    }
+
+    @Test
+    public void whenUserChangesSetting_saveSettingForCurrentState() {
+        mFakeSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                /* value= */"0:1:1:2",
+                UserHandle.USER_CURRENT);
+        mFakeRotationPolicy.setRotationLock(true);
+        mDeviceStateRotationLockSettingController.initialize();
+
+        mDeviceStateCallback.onStateChanged(0);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+        mDeviceStateRotationLockSettingController
+                .onRotationLockStateChanged(/* rotationLocked= */false,
+                        /* affordanceVisible= */ true);
+
+        assertThat(mFakeSettings
+                .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                        UserHandle.USER_CURRENT))
+                .isEqualTo("0:2:1:2");
+    }
+
+
+    @Test
+    public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
+        mFakeSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                /* value= */"0:0:1:2",
+                UserHandle.USER_CURRENT);
+        mFakeRotationPolicy.setRotationLock(true);
+        mDeviceStateRotationLockSettingController.initialize();
+
+        mDeviceStateCallback.onStateChanged(1);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+        mDeviceStateCallback.onStateChanged(0);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+    }
+
+    @Test
+    public void whenDeviceStateSwitchedToIgnoredState_newSettingsSaveForPreviousState() {
+        mFakeSettings.putStringForUser(
+                Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                /* value= */"0:0:1:2",
+                UserHandle.USER_CURRENT);
+        mFakeRotationPolicy.setRotationLock(true);
+        mDeviceStateRotationLockSettingController.initialize();
+
+        mDeviceStateCallback.onStateChanged(1);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+        mDeviceStateCallback.onStateChanged(0);
+        assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+        mDeviceStateRotationLockSettingController
+                .onRotationLockStateChanged(/* rotationLocked= */true,
+                        /* affordanceVisible= */ true);
+
+        assertThat(mFakeSettings
+                .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+                        UserHandle.USER_CURRENT))
+                .isEqualTo("0:0:1:1");
+    }
+
+    private static class FakeRotationPolicy implements RotationPolicyWrapper {
+
+        private boolean mRotationLock;
+
+        @Override
+        public void setRotationLock(boolean enabled) {
+            mRotationLock = enabled;
+        }
+
+        @Override
+        public void setRotationLockAtAngle(boolean enabled, int rotation) {
+            mRotationLock = enabled;
+        }
+
+        @Override
+        public int getRotationLockOrientation() {
+            throw new AssertionError("Not implemented");
+        }
+
+        @Override
+        public boolean isRotationLockToggleVisible() {
+            throw new AssertionError("Not implemented");
+        }
+
+        @Override
+        public boolean isRotationLocked() {
+            return mRotationLock;
+        }
+
+        @Override
+        public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
+                int userHandle) {
+            throw new AssertionError("Not implemented");
+        }
+
+        @Override
+        public void unregisterRotationPolicyListener(
+                RotationPolicy.RotationPolicyListener listener) {
+            throw new AssertionError("Not implemented");
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index f2de26c..21c4a17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
new file mode 100644
index 0000000..0581264
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class RotationLockControllerImplTest extends SysuiTestCase {
+
+    private static final String[] DEFAULT_SETTINGS = new String[]{
+            "0:0",
+            "1:2"
+    };
+
+    @Mock RotationPolicyWrapper mRotationPolicyWrapper;
+    @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+
+    private TestableResources mResources;
+    private ArgumentCaptor<RotationPolicy.RotationPolicyListener>
+            mRotationPolicyListenerCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(/* testClass= */ this);
+        mResources = mContext.getOrCreateTestableResources();
+
+        mRotationPolicyListenerCaptor = ArgumentCaptor.forClass(
+                RotationPolicy.RotationPolicyListener.class);
+    }
+
+    @Test
+    public void whenFlagOff_doesntInteractWithDeviceStateRotationController() {
+        createRotationLockController(new String[0]);
+
+        verifyZeroInteractions(mDeviceStateRotationLockSettingController);
+    }
+
+    @Test
+    public void whenFlagOn_setListeningSetsListeningOnDeviceStateRotationController() {
+        createRotationLockController();
+
+        verify(mDeviceStateRotationLockSettingController).setListening(/* listening= */ true);
+    }
+
+    @Test
+    public void whenFlagOn_initializesDeviceStateRotationController() {
+        createRotationLockController();
+
+        verify(mDeviceStateRotationLockSettingController).initialize();
+    }
+
+    @Test
+    public void whenFlagOn_dviceStateRotationControllerAddedToCallbacks() {
+        createRotationLockController();
+        captureRotationPolicyListener().onChange();
+
+        verify(mDeviceStateRotationLockSettingController)
+                .onRotationLockStateChanged(anyBoolean(), anyBoolean());
+    }
+
+    private RotationPolicy.RotationPolicyListener captureRotationPolicyListener() {
+        verify(mRotationPolicyWrapper)
+                .registerRotationPolicyListener(mRotationPolicyListenerCaptor.capture(), anyInt());
+        return mRotationPolicyListenerCaptor.getValue();
+    }
+
+    private void createRotationLockController() {
+        createRotationLockController(DEFAULT_SETTINGS);
+    }
+    private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
+        new RotationLockControllerImpl(
+                mRotationPolicyWrapper,
+                mDeviceStateRotationLockSettingController,
+                deviceStateRotationLockDefaults
+        );
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index c365ef2..b1b9ff4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.policy
 
 import android.app.IActivityTaskManager
+import android.app.admin.DevicePolicyManager
 import android.content.Context
 import android.content.DialogInterface
 import android.content.Intent
@@ -63,6 +64,8 @@
 @SmallTest
 class UserSwitcherControllerTest : SysuiTestCase() {
     @Mock private lateinit var keyguardStateController: KeyguardStateController
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock private lateinit var devicePolicyManager: DevicePolicyManager
     @Mock private lateinit var handler: Handler
     @Mock private lateinit var userTracker: UserTracker
     @Mock private lateinit var userManager: UserManager
@@ -107,6 +110,8 @@
                 userManager,
                 userTracker,
                 keyguardStateController,
+                deviceProvisionedController,
+                devicePolicyManager,
                 handler,
                 activityStarter,
                 broadcastDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 07d3fc2..f6a54936 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -52,9 +52,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 5efe05f..84e6df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -60,9 +60,9 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
index 8f07545..a34c598 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -60,6 +61,85 @@
     }
 
     @Test
+    public void testInitiallyAbovePrimary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(false, 0);
+        assertNotNull(listener.mLastEvent);
+        assertFalse(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
+    public void testInitiallyBelowPrimaryAboveSecondary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(true, 0);
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorSecondary.triggerEvent(false, 1);
+        assertNotNull(listener.mLastEvent);
+        assertFalse(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
+    public void testInitiallyBelowPrimaryAndSecondary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(true, 0);
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorSecondary.triggerEvent(true, 1);
+        assertNotNull(listener.mLastEvent);
+        assertTrue(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
+    public void testPrimaryBelowDoesNotInvokeSecondary() {
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        // Trigger primary sensor. Our secondary sensor is not registered.
+        mThresholdSensorPrimary.triggerEvent(false, 0);
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+    }
+
+    @Test
     public void testSingleListener() {
         TestableListener listener = new TestableListener();
 
@@ -256,40 +336,6 @@
     }
 
     @Test
-    public void testPrimaryCancelsSecondary() {
-        TestableListener listener = new TestableListener();
-
-        mProximitySensor.register(listener);
-        assertFalse(mThresholdSensorPrimary.isPaused());
-        assertTrue(mThresholdSensorSecondary.isPaused());
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
-
-        mThresholdSensorPrimary.triggerEvent(true, 0);
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
-        mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertTrue(listener.mLastEvent.getBelow());
-        assertEquals(1, listener.mCallCount);
-
-        // When the primary reports false, the secondary is no longer needed. We get an immediate
-        // report.
-        mThresholdSensorPrimary.triggerEvent(false, 1);
-        assertFalse(listener.mLastEvent.getBelow());
-        assertEquals(2, listener.mCallCount);
-
-        // The secondary is now ignored. No more work is scheduled.
-        mFakeExecutor.advanceClockToNext();
-        mFakeExecutor.runNextReady();
-        mThresholdSensorSecondary.triggerEvent(true, 0);
-        assertFalse(listener.mLastEvent.getBelow());
-        assertEquals(2, listener.mCallCount);
-        assertEquals(0, mFakeExecutor.numPending());
-
-        mProximitySensor.unregister(listener);
-    }
-
-    @Test
     public void testSecondaryCancelsSecondary() {
         TestableListener listener = new TestableListener();
         ThresholdSensor.Listener cancelingListener = new ThresholdSensor.Listener() {
@@ -342,7 +388,7 @@
 
         // The secondary sensor should now remain resumed indefinitely.
         assertFalse(mThresholdSensorSecondary.isPaused());
-        mThresholdSensorPrimary.triggerEvent(false, 1);
+        mThresholdSensorSecondary.triggerEvent(false, 1);
         assertFalse(listener.mLastEvent.getBelow());
         assertEquals(2, listener.mCallCount);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 6976422..7bb2674 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -31,6 +31,7 @@
     private final Map<SettingsKey, String> mValues = new HashMap<>();
     private final Map<SettingsKey, List<ContentObserver>> mContentObservers =
             new HashMap<>();
+    private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
 
     public static final Uri CONTENT_URI = Uri.parse("content://settings/fake");
 
@@ -55,9 +56,15 @@
     @Override
     public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
             ContentObserver settingsObserver, int userHandle) {
-        SettingsKey key = new SettingsKey(userHandle, uri.toString());
-        mContentObservers.putIfAbsent(key, new ArrayList<>());
-        List<ContentObserver> observers = mContentObservers.get(key);
+        List<ContentObserver> observers;
+        if (userHandle == UserHandle.USER_ALL) {
+            mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>());
+            observers = mContentObserversAllUsers.get(uri.toString());
+        } else {
+            SettingsKey key = new SettingsKey(userHandle, uri.toString());
+            mContentObservers.putIfAbsent(key, new ArrayList<>());
+            observers = mContentObservers.get(key);
+        }
         observers.add(settingsObserver);
     }
 
@@ -67,6 +74,10 @@
             List<ContentObserver> observers = mContentObservers.get(key);
             observers.remove(settingsObserver);
         }
+        for (String key : mContentObserversAllUsers.keySet()) {
+            List<ContentObserver> observers = mContentObserversAllUsers.get(key);
+            observers.remove(settingsObserver);
+        }
     }
 
     @Override
@@ -114,6 +125,10 @@
         for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) {
             observer.dispatchChange(false, List.of(uri), userHandle);
         }
+        for (ContentObserver observer :
+                mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) {
+            observer.dispatchChange(false, List.of(uri), userHandle);
+        }
         return true;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index 0d560f2..34cae58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.database.ContentObserver;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 
@@ -89,6 +90,16 @@
     }
 
     @Test
+    public void testRegisterContentObserverAllUsers() {
+        mFakeSettings.registerContentObserverForUser(
+                mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+
+        mFakeSettings.putString("cat", "hat");
+
+        verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt());
+    }
+
+    @Test
     public void testUnregisterContentObserver() {
         mFakeSettings.registerContentObserver("cat", mContentObserver);
         mFakeSettings.unregisterContentObserver(mContentObserver);
@@ -98,4 +109,16 @@
         verify(mContentObserver, never()).dispatchChange(
                 anyBoolean(), any(Collection.class), anyInt());
     }
+
+    @Test
+    public void testUnregisterContentObserverAllUsers() {
+        mFakeSettings.registerContentObserverForUser(
+                mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+        mFakeSettings.unregisterContentObserver(mContentObserver);
+
+        mFakeSettings.putString("cat", "hat");
+
+        verify(mContentObserver, never()).dispatchChange(
+                anyBoolean(), any(Collection.class), anyInt());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index a0b93ad..9f755f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -76,11 +76,11 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.RankingBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index b0dd73a..a3bbb26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -64,10 +64,10 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index eec875a..b88366b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1704,6 +1704,10 @@
      * @param displayId The logical display id.
      */
     private void ensureWindowsAvailableTimedLocked(int displayId) {
+        if (displayId == Display.INVALID_DISPLAY) {
+            return;
+        }
+
         if (mA11yWindowManager.getWindowListLocked(displayId) != null) {
             return;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7b2b8e4..fd05c23 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1322,7 +1322,7 @@
      */
     public boolean accessibilityFocusOnlyInActiveWindow() {
         synchronized (mLock) {
-            return mA11yWindowManager.isTrackingWindowsLocked();
+            return mA11yWindowManager.accessibilityFocusOnlyInActiveWindowLocked();
         }
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 0a68d71..09485d1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -1383,20 +1383,9 @@
             // the touched window are delivered is fine.
             final int oldActiveWindow = mActiveWindowId;
             setActiveWindowLocked(mTopFocusedWindowId);
-
-            // If there is no service that can operate with interactive windows
-            // then we keep the old behavior where a window loses accessibility
-            // focus if it is no longer active. This still changes the behavior
-            // for services that do not operate with interactive windows and run
-            // at the same time as the one(s) which does. In practice however,
-            // there is only one service that uses accessibility focus and it
-            // is typically the one that operates with interactive windows, So,
-            // this is fine. Note that to allow a service to work across windows
-            // we have to allow accessibility focus stay in any of them. Sigh...
-            final boolean accessibilityFocusOnlyInActiveWindow = !isTrackingWindowsLocked();
             if (oldActiveWindow != mActiveWindowId
                     && mAccessibilityFocusedWindowId == oldActiveWindow
-                    && accessibilityFocusOnlyInActiveWindow) {
+                    && accessibilityFocusOnlyInActiveWindowLocked()) {
                 clearAccessibilityFocusLocked(oldActiveWindow);
             }
         }
@@ -1617,6 +1606,15 @@
         return displayList;
     }
 
+    // If there is no service that can operate with interactive windows
+    // then a window loses accessibility focus if it is no longer active.
+    // This inspection happens when the user interaction is ended.
+    // Note that to allow a service to work across windows,
+    // we have to allow accessibility focus stay in any of them.
+    boolean accessibilityFocusOnlyInActiveWindowLocked() {
+        return !isTrackingWindowsLocked();
+    }
+
     /**
      * Gets current input focused window token from window manager, and returns its windowId.
      *
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 6dabe76..6ff0826 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -98,7 +98,6 @@
             mLastReceivedEvent.recycle();
             mLastReceivedEvent = null;
         }
-        mLastTouchedWindowId = -1;
         mReceivedPointerTracker.clear();
         mInjectedPointersDown = 0;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 8aacafb..19601b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -189,10 +189,10 @@
             if (animationCallback.mCurrentMode == targetMode) {
                 animationCallback.restoreToCurrentMagnificationMode();
                 return;
+            } else {
+                Slog.w(TAG, "discard duplicate request");
+                return;
             }
-            Slog.w(TAG, "request during transition, abandon current:"
-                    + animationCallback.mTargetMode);
-            animationCallback.setExpiredAndRemoveFromListLocked();
         }
 
         if (magnificationCenter == null) {
@@ -464,7 +464,9 @@
         private final TransitionCallBack mTransitionCallBack;
         private boolean mExpired = false;
         private final int mDisplayId;
+        // The mode the in-progress animation is going to.
         private final int mTargetMode;
+        // The mode the in-progress animation is going from.
         private final int mCurrentMode;
         private final float mCurrentScale;
         private final PointF mCurrentCenter = new PointF();
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index cd332a6..4946ad4 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -125,7 +125,7 @@
             // connect with remote AppPredictionService instead for dark launch
             usesPeopleService = false;
         }
-        final boolean serviceExists = resolveService(sessionId, false,
+        final boolean serviceExists = resolveService(sessionId, true,
                 usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
         if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
             final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 11df871..3540a33 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -98,6 +98,7 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -351,6 +352,8 @@
     @Nullable
     private ClientSuggestionsSession mClientSuggestionsSession;
 
+    private final AccessibilityManager mAccessibilityManager;
+
     void onSwitchInputMethodLocked() {
         // One caveat is that for the case where the focus is on a field for which regular autofill
         // returns null, and augmented autofill is triggered,  and then the user switches the input
@@ -449,6 +452,7 @@
                     if (!mWaitForInlineRequest || mPendingInlineSuggestionsRequest != null) {
                         return;
                     }
+                    mWaitForInlineRequest = inlineSuggestionsRequest != null;
                     mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
                     maybeRequestFillFromServiceLocked();
                     viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST);
@@ -472,7 +476,10 @@
                     return;
                 }
 
-                if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
+                // If a11y touch exploration is enabled, then we do not send an inline fill request
+                // to the regular af service, because dropdown UI is easier to use.
+                if (mPendingInlineSuggestionsRequest.isServiceSupported()
+                        && !mAccessibilityManager.isTouchExplorationEnabled()) {
                     mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
                             mPendingFillRequest.getFillContexts(),
                             mPendingFillRequest.getClientState(),
@@ -941,6 +948,7 @@
         mRemoteFillService = serviceComponentName == null ? null
                 : new RemoteFillService(context, serviceComponentName, userId, this,
                         bindInstantServiceAllowed);
+        mAccessibilityManager = AccessibilityManager.getInstance(context);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 4127556..28a40eb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -17,6 +17,7 @@
 
 package com.android.server.companion;
 
+import static android.Manifest.permission.BIND_COMPANION_DEVICE_SERVICE;
 import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
 import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
 import static android.content.Context.BIND_IMPORTANT;
@@ -1234,6 +1235,12 @@
                     + " has " + packageResolveInfos.size());
             return new ServiceConnector.NoOp<>();
         }
+        String servicePermission = packageResolveInfos.get(0).serviceInfo.permission;
+        if (!BIND_COMPANION_DEVICE_SERVICE.equals(servicePermission)) {
+            Slog.w(LOG_TAG, "Binding CompanionDeviceService must have "
+                    + BIND_COMPANION_DEVICE_SERVICE + " permission.");
+            return new ServiceConnector.NoOp<>();
+        }
         ComponentName componentName = packageResolveInfos.get(0).serviceInfo.getComponentName();
         Slog.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
         return new ServiceConnector.Impl<ICompanionDeviceService>(getContext(),
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 282b868..689890f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -92,6 +92,7 @@
     name: "services.core.unboosted",
     defaults: ["platform_service_defaults"],
     srcs: [
+        ":android.hardware.biometrics.face-V1-java-source",
         ":statslog-art-java-gen",
         ":services.core-sources",
         ":services.core.protologsrc",
@@ -116,6 +117,7 @@
 
     libs: [
         "services.net",
+        "android.hardware.common-V2-java",
         "android.hardware.light-V2.0-java",
         "android.hardware.gnss-V1-java",
         "android.hardware.power-V1-java",
@@ -145,7 +147,6 @@
         "android.hardware.light-V1-java",
         "android.hardware.tv.cec-V1.1-java",
         "android.hardware.weaver-V1.0-java",
-        "android.hardware.biometrics.face-V1-java",
         "android.hardware.biometrics.face-V1.0-java",
         "android.hardware.biometrics.fingerprint-V2.3-java",
         "android.hardware.biometrics.fingerprint-V1-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 0621d0f..e390ae28 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -353,6 +353,12 @@
 
 
     /**
+     * Retrieve all receivers that can handle a broadcast of the given intent.
+     */
+    public abstract List<ResolveInfo> queryIntentReceivers(Intent intent,
+            String resolvedType, int flags, int filterCallingUid, int userId);
+
+    /**
      * Retrieve all services that can be performed for the given intent.
      * @see PackageManager#queryIntentServices(Intent, int)
      */
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b4912bb..31061190b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2509,6 +2509,16 @@
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions());
     }
 
+    private boolean isBleState(int state) {
+        switch (state) {
+            case BluetoothAdapter.STATE_BLE_ON:
+            case BluetoothAdapter.STATE_BLE_TURNING_ON:
+            case BluetoothAdapter.STATE_BLE_TURNING_OFF:
+                return true;
+        }
+        return false;
+    }
+
     @RequiresPermission(allOf = {
             android.Manifest.permission.BLUETOOTH_CONNECT,
             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -2531,8 +2541,15 @@
                 sendBluetoothServiceDownCallback();
                 unbindAndFinish();
                 sendBleStateChanged(prevState, newState);
-                // Don't broadcast as it has already been broadcast before
-                isStandardBroadcast = false;
+
+                /* Currently, the OFF intent is broadcasted externally only when we transition
+                 * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state,
+                 * we are guaranteed that the OFF intent has been broadcasted earlier and we
+                 * can safely skip it.
+                 * Conversely, if the previous state is not a BLE state, it indicates that some
+                 * sort of crash has occurred, moving us directly to STATE_OFF without ever
+                 * passing through BLE_ON. We should broadcast the OFF intent in this case. */
+                isStandardBroadcast = !isBleState(prevState);
 
             } else if (!intermediate_off) {
                 // connect to GattService
@@ -2585,6 +2602,11 @@
                 // Show prevState of BLE_ON as OFF to standard users
                 prevState = BluetoothAdapter.STATE_OFF;
             }
+            if (DBG) {
+                Slog.d(TAG,
+                        "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
+                                + BluetoothAdapter.nameForState(newState));
+            }
             Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
             intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
             intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 047aae7..aae1cc0 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -147,6 +147,47 @@
         return true;
     }
 
+    /**
+     * Returns whether an intent matches the IntentFilter with a pre-resolved type.
+     */
+    public static boolean intentMatchesFilter(
+            IntentFilter filter, Intent intent, String resolvedType) {
+        final boolean debug = localLOGV
+                || ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
+
+        final Printer logPrinter = debug
+                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM) : null;
+
+        if (debug) {
+            Slog.v(TAG, "Intent: " + intent);
+            Slog.v(TAG, "Matching against filter: " + filter);
+            filter.dump(logPrinter, "  ");
+        }
+
+        final int match = filter.match(intent.getAction(), resolvedType, intent.getScheme(),
+                intent.getData(), intent.getCategories(), TAG);
+
+        if (match >= 0) {
+            if (debug) {
+                Slog.v(TAG, "Filter matched!  match=0x" + Integer.toHexString(match));
+            }
+            return true;
+        } else {
+            if (debug) {
+                final String reason;
+                switch (match) {
+                    case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
+                    case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
+                    case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
+                    case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
+                    default: reason = "unknown reason"; break;
+                }
+                Slog.v(TAG, "Filter did not match: " + reason);
+            }
+            return false;
+        }
+    }
+
     private ArrayList<F> collectFilters(F[] array, IntentFilter matching) {
         ArrayList<F> res = null;
         if (array != null) {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 44dc929..d5ea5bf 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -21,8 +21,6 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.ActivityManager.RunningServiceInfo;
 import static android.app.ActivityManager.RunningTaskInfo;
-import static android.app.ActivityManager.getCurrentUser;
-import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
@@ -383,17 +381,9 @@
 
             int sensor;
             if (result == MODE_IGNORED) {
-                if (code == OP_RECORD_AUDIO) {
+                if (code == OP_RECORD_AUDIO || code == OP_PHONE_CALL_MICROPHONE) {
                     sensor = MICROPHONE;
-                } else if (code == OP_CAMERA) {
-                    sensor = CAMERA;
-                } else {
-                    return;
-                }
-            } else if (result == MODE_ALLOWED) {
-                if (code == OP_PHONE_CALL_MICROPHONE) {
-                    sensor = MICROPHONE;
-                } else if (code == OP_PHONE_CALL_CAMERA) {
+                } else if (code == OP_CAMERA || code == OP_PHONE_CALL_CAMERA) {
                     sensor = CAMERA;
                 } else {
                     return;
@@ -423,6 +413,12 @@
                 return;
             }
 
+            if (uid == Process.SYSTEM_UID) {
+                // If the system uid is being blamed for sensor access, the ui must be shown
+                // explicitly using SensorPrivacyManager#showSensorUseDialog
+                return;
+            }
+
             synchronized (mLock) {
                 if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
                     Log.d(TAG,
@@ -431,11 +427,6 @@
                 }
             }
 
-            if (uid == Process.SYSTEM_UID) {
-                enqueueSensorUseReminderDialogAsync(-1, user, packageName, sensor);
-                return;
-            }
-
             // TODO: Handle reminders with multiple sensors
 
             // - If we have a likely activity that triggered the sensor use overlay a dialog over
@@ -718,6 +709,9 @@
         public void setIndividualSensorPrivacy(@UserIdInt int userId,
                 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
             enforceManageSensorPrivacyPermission();
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = mCurrentUser;
+            }
             if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
                 return;
             }
@@ -843,6 +837,9 @@
         public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
                 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
             enforceManageSensorPrivacyPermission();
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = mCurrentUser;
+            }
             int parentId = mUserManagerInternal.getProfileParentId(userId);
             forAllUsers(userId2 -> {
                 if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -896,6 +893,9 @@
         @Override
         public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
             enforceObserveSensorPrivacyPermission();
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = mCurrentUser;
+            }
             synchronized (mLock) {
                 return isIndividualSensorPrivacyEnabledLocked(userId, sensor);
             }
@@ -1213,6 +1213,9 @@
         public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
                 IBinder token, boolean suppress) {
             enforceManageSensorPrivacyPermission();
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = mCurrentUser;
+            }
             Objects.requireNonNull(token);
 
             Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId));
@@ -1239,6 +1242,18 @@
             }
         }
 
+        @Override
+        public void showSensorUseDialog(int sensor) {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                throw new SecurityException("Can only be called by the system uid");
+            }
+            if (!isIndividualSensorPrivacyEnabled(mCurrentUser, sensor)) {
+                return;
+            }
+            enqueueSensorUseReminderDialogAsync(
+                    -1, UserHandle.of(mCurrentUser), "android", sensor);
+        }
+
         private void userSwitching(int from, int to) {
             boolean micState;
             boolean camState;
@@ -1265,10 +1280,14 @@
                 case MICROPHONE:
                     mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled,
                             mAppOpsRestrictionToken);
+                    mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled,
+                            mAppOpsRestrictionToken);
                     break;
                 case CAMERA:
                     mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
                             mAppOpsRestrictionToken);
+                    mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_CAMERA, enabled,
+                            mAppOpsRestrictionToken);
                     break;
             }
         }
@@ -1898,9 +1917,9 @@
                 if (!mIsInEmergencyCall) {
                     mIsInEmergencyCall = true;
                     if (mSensorPrivacyServiceImpl
-                            .isIndividualSensorPrivacyEnabled(getCurrentUser(), MICROPHONE)) {
+                            .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
                         mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
-                                getCurrentUser(), OTHER, MICROPHONE, false);
+                                mCurrentUser, OTHER, MICROPHONE, false);
                         mMicUnmutedForEmergencyCall = true;
                     } else {
                         mMicUnmutedForEmergencyCall = false;
@@ -1915,7 +1934,7 @@
                     mIsInEmergencyCall = false;
                     if (mMicUnmutedForEmergencyCall) {
                         mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
-                                getCurrentUser(), OTHER, MICROPHONE, true);
+                                mCurrentUser, OTHER, MICROPHONE, true);
                         mMicUnmutedForEmergencyCall = false;
                     }
                 }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 85eadf5..1007130 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1168,8 +1168,8 @@
 
     private boolean doesPackageHaveCallingUid(@NonNull String packageName) {
         try {
-            return getContext().getPackageManager().getPackageUid(packageName, 0)
-                    == mInjector.getCallingUid();
+            return getContext().getPackageManager().getPackageUidAsUser(packageName,
+                    UserHandle.getCallingUserId()) == mInjector.getCallingUid();
         } catch (PackageManager.NameNotFoundException e) {
             return false;
         }
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index d483f18..a03425c 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -26,6 +26,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IVpnManager;
@@ -312,6 +314,26 @@
         }
     }
 
+    // TODO : Move to a static lib to factorize with Vpn.java
+    private int getAppUid(final String app, final int userId) {
+        final PackageManager pm = mContext.getPackageManager();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return pm.getPackageUidAsUser(app, userId);
+        } catch (NameNotFoundException e) {
+            return -1;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private void verifyCallingUidAndPackage(String packageName, int callingUid) {
+        final int userId = UserHandle.getUserId(callingUid);
+        if (getAppUid(packageName, userId) != callingUid) {
+            throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+        }
+    }
+
     /**
      * Starts the VPN based on the stored profile for the given package
      *
@@ -323,7 +345,9 @@
      */
     @Override
     public void startVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final int callingUid = Binder.getCallingUid();
+        verifyCallingUidAndPackage(packageName, callingUid);
+        final int user = UserHandle.getUserId(callingUid);
         synchronized (mVpns) {
             throwIfLockdownEnabled();
             mVpns.get(user).startVpnProfile(packageName);
@@ -340,7 +364,9 @@
      */
     @Override
     public void stopVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final int callingUid = Binder.getCallingUid();
+        verifyCallingUidAndPackage(packageName, callingUid);
+        final int user = UserHandle.getUserId(callingUid);
         synchronized (mVpns) {
             mVpns.get(user).stopVpnProfile(packageName);
         }
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 1f35b88..f591b26 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -1361,7 +1361,10 @@
                 if (args.length > 1) {
                     hostname = args[1];
                 }
-                PairDevice device = new PairDevice(fingerprints, hostname, false);
+                PairDevice device = new PairDevice();
+                device.name = fingerprints;
+                device.guid = hostname;
+                device.connected = false;
                 intent.putExtra(AdbManager.WIRELESS_PAIR_DEVICE_EXTRA, device);
                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
                 // Add the key into the keystore
@@ -1843,8 +1846,11 @@
                 if (args.length > 1) {
                     hostname = args[1];
                 }
-                pairedDevices.put(keyEntry.getKey(), new PairDevice(
-                        hostname, fingerprints, mWifiConnectedKeys.contains(keyEntry.getKey())));
+                PairDevice pairDevice = new PairDevice();
+                pairDevice.name = hostname;
+                pairDevice.guid = fingerprints;
+                pairDevice.connected = mWifiConnectedKeys.contains(keyEntry.getKey());
+                pairedDevices.put(keyEntry.getKey(), pairDevice);
             }
             return pairedDevices;
         }
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 29bb542..7a4d2ce 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -27,6 +27,8 @@
 import android.debug.AdbManager;
 import android.debug.AdbManagerInternal;
 import android.debug.AdbTransportType;
+import android.debug.FingerprintAndPairDevice;
+import android.debug.IAdbCallback;
 import android.debug.IAdbManager;
 import android.debug.IAdbTransport;
 import android.debug.PairDevice;
@@ -35,6 +37,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -87,6 +90,7 @@
     private final AdbConnectionPortListener mPortListener = new AdbConnectionPortListener();
     private AdbDebuggingManager.AdbConnectionPortPoller mConnectionPortPoller;
 
+    private final RemoteCallbackList<IAdbCallback> mCallbacks = new RemoteCallbackList<>();
     /**
      * Manages the service lifecycle for {@code AdbService} in {@code SystemServer}.
      */
@@ -348,12 +352,21 @@
     }
 
     @Override
-    public Map<String, PairDevice> getPairedDevices() {
+    public FingerprintAndPairDevice[] getPairedDevices() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
-        if (mDebuggingManager != null) {
-            return mDebuggingManager.getPairedDevices();
+        if (mDebuggingManager == null) {
+            return null;
         }
-        return null;
+        Map<String, PairDevice> map = mDebuggingManager.getPairedDevices();
+        FingerprintAndPairDevice[] ret = new FingerprintAndPairDevice[map.size()];
+        int i = 0;
+        for (Map.Entry<String, PairDevice> entry : map.entrySet()) {
+            ret[i] = new FingerprintAndPairDevice();
+            ret[i].keyFingerprint = entry.getKey();
+            ret[i].device = entry.getValue();
+            i++;
+        }
+        return ret;
     }
 
     @Override
@@ -401,6 +414,21 @@
         return mConnectionPort.get();
     }
 
+    @Override
+    public void registerCallback(IAdbCallback callback) throws RemoteException {
+        if (DEBUG) {
+            Slog.d(TAG, "Registering callback " + callback);
+        }
+        mCallbacks.register(callback);
+    }
+
+    @Override
+    public void unregisterCallback(IAdbCallback callback) throws RemoteException {
+        if (DEBUG) {
+            Slog.d(TAG, "Unregistering callback " + callback);
+        }
+        mCallbacks.unregister(callback);
+    }
     /**
      * This listener is only used when ro.adb.secure=0. Otherwise, AdbDebuggingManager will
      * do this.
@@ -507,6 +535,23 @@
         if (mDebuggingManager != null) {
             mDebuggingManager.setAdbEnabled(enable, transportType);
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "Broadcasting enable = " + enable + ", type = " + transportType);
+        }
+        mCallbacks.broadcast((callback) -> {
+            if (DEBUG) {
+                Slog.d(TAG, "Sending enable = " + enable + ", type = " + transportType
+                        + " to " + callback);
+            }
+            try {
+                callback.onDebuggingChanged(enable, transportType);
+            } catch (RemoteException ex) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Unable to send onDebuggingChanged:", ex);
+                }
+            }
+        });
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 07847f1..2483fb8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -102,6 +102,7 @@
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
 import android.content.ComponentName;
 import android.content.ComponentName.WithComponentName;
 import android.content.Context;
@@ -152,7 +153,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -164,6 +164,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
+import com.android.server.am.LowMemDetector.MemFactor;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 
@@ -173,6 +174,7 @@
 import java.io.StringWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
@@ -307,6 +309,7 @@
      */
     @ChangeId
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+    @Overridable
     static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
 
     /**
@@ -333,7 +336,9 @@
         @Override
         public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
             synchronized (mAm) {
-                stopAllForegroundServicesLocked(uid, packageName);
+                if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
+                    stopAllForegroundServicesLocked(uid, packageName);
+                }
             }
         }
     }
@@ -607,6 +612,17 @@
         return (mode != AppOpsManager.MODE_ALLOWED);
     }
 
+    void updateAppRestrictedAnyInBackgroundLocked(final int uid, final String packageName) {
+        final boolean restricted = appRestrictedAnyInBackground(uid, packageName);
+        final UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(uid);
+        if (uidRec != null) {
+            final ProcessRecord app = uidRec.getProcessInPackage(packageName);
+            if (app != null) {
+                app.mState.setBackgroundRestricted(restricted);
+            }
+        }
+    }
+
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
             int callingPid, int callingUid, boolean fgRequired, String callingPackage,
             @Nullable String callingFeatureId, final int userId)
@@ -805,10 +821,12 @@
 
         if (fgRequired) {
             // We are now effectively running a foreground service.
-            ServiceState stracker = r.getTracker();
-            if (stracker != null) {
-                stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
-                        r.lastActivity);
+            synchronized (mAm.mProcessStats.mLock) {
+                final ServiceState stracker = r.getTracker();
+                if (stracker != null) {
+                    stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
+                            r.lastActivity);
+                }
             }
             mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
@@ -1080,9 +1098,11 @@
 
     ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
             boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
-        ServiceState stracker = r.getTracker();
-        if (stracker != null) {
-            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+        synchronized (mAm.mProcessStats.mLock) {
+            final ServiceState stracker = r.getTracker();
+            if (stracker != null) {
+                stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+            }
         }
         r.callStart = false;
 
@@ -1142,8 +1162,10 @@
         mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
         service.startRequested = false;
         if (service.tracker != null) {
-            service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
-                    SystemClock.uptimeMillis());
+            synchronized (mAm.mProcessStats.mLock) {
+                service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                        SystemClock.uptimeMillis());
+            }
         }
         service.callStart = false;
 
@@ -1318,8 +1340,10 @@
             mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
             r.startRequested = false;
             if (r.tracker != null) {
-                r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
-                        SystemClock.uptimeMillis());
+                synchronized (mAm.mProcessStats.mLock) {
+                    r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
+                }
             }
             r.callStart = false;
             final long origId = Binder.clearCallingIdentity();
@@ -1438,7 +1462,8 @@
                     if (!aa.mAppOnTop) {
                         // Transitioning a fg-service host app out of top: if it's bg restricted,
                         // it loses the fg service state now.
-                        if (!appRestrictedAnyInBackground(aa.mUid, aa.mPackageName)) {
+                        if (isForegroundServiceAllowedInBackgroundRestricted(
+                                aa.mUid, aa.mPackageName)) {
                             if (active == null) {
                                 active = new ArrayList<>();
                             }
@@ -1656,8 +1681,38 @@
         }
     }
 
-    private boolean appIsTopLocked(int uid) {
-        return mAm.getUidStateLocked(uid) <= PROCESS_STATE_TOP;
+    /**
+     * Check if the given app is allowed to have FGS running even if it's background restricted.
+     *
+     * <p>
+     * Currently it needs to be in Top/Bound Top/FGS state. An uid could be in the FGS state if:
+     * a) Bound by another process in the FGS state;
+     * b) There is an active FGS running (ServiceRecord.isForeground is true);
+     * c) The startForegroundService() has been called but the startForeground() hasn't - in this
+     *    case, it must have passed the background FGS start check so we're safe here.
+     * </p>
+     */
+    private boolean isForegroundServiceAllowedInBackgroundRestricted(ProcessRecord app) {
+        final ProcessStateRecord state = app.mState;
+        if (!state.isBackgroundRestricted()
+                || state.getSetProcState() <= ActivityManager.PROCESS_STATE_BOUND_TOP) {
+            return true;
+        }
+        if (state.getSetProcState() == ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+                && state.isSetBoundByNonBgRestrictedApp()) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check if the given uid/pkg is allowed to have FGS running even if it's background restricted.
+     */
+    private boolean isForegroundServiceAllowedInBackgroundRestricted(int uid, String packageName) {
+        final UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(uid);
+        ProcessRecord app = null;
+        return uidRec != null && ((app = uidRec.getProcessInPackage(packageName)) != null)
+                && isForegroundServiceAllowedInBackgroundRestricted(app);
     }
 
     /**
@@ -1751,8 +1806,7 @@
                 // Apps that are TOP or effectively similar may call startForeground() on
                 // their services even if they are restricted from doing that while in bg.
                 if (!ignoreForeground
-                        && !appIsTopLocked(r.appInfo.uid)
-                        && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
+                        && !isForegroundServiceAllowedInBackgroundRestricted(r.app)) {
                     Slog.w(TAG,
                             "Service.startForeground() not allowed due to bg restriction: service "
                                     + r.shortInstanceName);
@@ -1875,10 +1929,12 @@
                         r.mStartForegroundCount++;
                         r.mFgsEnterTime = SystemClock.uptimeMillis();
                         if (!stopProcStatsOp) {
-                            ServiceState stracker = r.getTracker();
-                            if (stracker != null) {
-                                stracker.setForeground(true,
-                                        mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+                            synchronized (mAm.mProcessStats.mLock) {
+                                final ServiceState stracker = r.getTracker();
+                                if (stracker != null) {
+                                    stracker.setForeground(true,
+                                            mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+                                }
                             }
                         } else {
                             stopProcStatsOp = false;
@@ -1913,10 +1969,12 @@
                 if (stopProcStatsOp) {
                     // We got through to this point with it actively being started foreground,
                     // and never decided we wanted to keep it like that, so drop it.
-                    ServiceState stracker = r.getTracker();
-                    if (stracker != null) {
-                        stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                                SystemClock.uptimeMillis());
+                    synchronized (mAm.mProcessStats.mLock) {
+                        final ServiceState stracker = r.getTracker();
+                        if (stracker != null) {
+                            stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+                                    SystemClock.uptimeMillis());
+                        }
                     }
                 }
                 if (alreadyStartedOp) {
@@ -1958,10 +2016,12 @@
 
                 r.isForeground = false;
                 r.mFgsExitTime = SystemClock.uptimeMillis();
-                ServiceState stracker = r.getTracker();
-                if (stracker != null) {
-                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
-                            SystemClock.uptimeMillis());
+                synchronized (mAm.mProcessStats.mLock) {
+                    final ServiceState stracker = r.getTracker();
+                    if (stracker != null) {
+                        stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+                                SystemClock.uptimeMillis());
+                    }
                 }
                 mAm.mAppOpsService.finishOperation(
                         AppOpsManager.getToken(mAm.mAppOpsService),
@@ -2736,10 +2796,12 @@
                 s.lastActivity = SystemClock.uptimeMillis();
                 if (!s.hasAutoCreateConnections()) {
                     // This is the first binding, let the tracker know.
-                    ServiceState stracker = s.getTracker();
-                    if (stracker != null) {
-                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
-                                s.lastActivity);
+                    synchronized (mAm.mProcessStats.mLock) {
+                        final ServiceState stracker = s.getTracker();
+                        if (stracker != null) {
+                            stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
+                                    s.lastActivity);
+                        }
                     }
                 }
             }
@@ -3376,9 +3438,11 @@
         ProcessServiceRecord psr;
         if (r.executeNesting == 0) {
             r.executeFg = fg;
-            ServiceState stracker = r.getTracker();
-            if (stracker != null) {
-                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
+            synchronized (mAm.mProcessStats.mLock) {
+                final ServiceState stracker = r.getTracker();
+                if (stracker != null) {
+                    stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
+                }
             }
             if (r.app != null) {
                 psr = r.app.mServices;
@@ -3467,6 +3531,8 @@
         final long now = SystemClock.uptimeMillis();
 
         final String reason;
+        final int oldPosInRestarting = mRestartingServices.indexOf(r);
+        boolean inRestarting = oldPosInRestarting != -1;
         if ((r.serviceInfo.applicationInfo.flags
                 &ApplicationInfo.FLAG_PERSISTENT) == 0) {
             long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
@@ -3534,56 +3600,89 @@
             }
 
             if (isServiceRestartBackoffEnabledLocked(r.packageName)) {
-                r.nextRestartTime = now + r.restartDelay;
+                r.nextRestartTime = r.mEarliestRestartTime = now + r.restartDelay;
 
-                // Make sure that we don't end up restarting a bunch of services
-                // all at the same time.
-                boolean repeat;
-                final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
-                do {
-                    repeat = false;
-                    for (int i = mRestartingServices.size() - 1; i >= 0; i--) {
-                        final ServiceRecord r2 = mRestartingServices.get(i);
-                        if (r2 != r
-                                && r.nextRestartTime >= (r2.nextRestartTime - restartTimeBetween)
-                                && r.nextRestartTime < (r2.nextRestartTime + restartTimeBetween)) {
-                            r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
-                            r.restartDelay = r.nextRestartTime - now;
-                            repeat = true;
-                            break;
+                if (inRestarting) {
+                    // Take it out of the list temporarily for easier maintenance of the list.
+                    mRestartingServices.remove(oldPosInRestarting);
+                    inRestarting = false;
+                }
+                if (mRestartingServices.isEmpty()) {
+                    // Apply the extra delay even if it's the only one in the list.
+                    final long extraDelay = getExtraRestartTimeInBetweenLocked();
+                    r.nextRestartTime = Math.max(now + extraDelay, r.nextRestartTime);
+                    r.restartDelay = r.nextRestartTime - now;
+                } else {
+                    // Make sure that we don't end up restarting a bunch of services
+                    // all at the same time.
+                    boolean repeat;
+                    final long restartTimeBetween = getExtraRestartTimeInBetweenLocked()
+                            + mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
+                    do {
+                        repeat = false;
+                        final long nextRestartTime = r.nextRestartTime;
+                        // mRestartingServices is sorted by nextRestartTime.
+                        for (int i = mRestartingServices.size() - 1; i >= 0; i--) {
+                            final ServiceRecord r2 = mRestartingServices.get(i);
+                            final long nextRestartTime2 = r2.nextRestartTime;
+                            if (nextRestartTime >= (nextRestartTime2 - restartTimeBetween)
+                                    && nextRestartTime < (nextRestartTime2 + restartTimeBetween)) {
+                                r.nextRestartTime = nextRestartTime2 + restartTimeBetween;
+                                r.restartDelay = r.nextRestartTime - now;
+                                repeat = true;
+                                break;
+                            } else if (nextRestartTime >= nextRestartTime2 + restartTimeBetween) {
+                                // This spot fulfills our needs, bail out.
+                                break;
+                            }
                         }
-                    }
-                } while (repeat);
+                    } while (repeat);
+                }
             } else {
                 // It's been forced to ignore the restart backoff, fix the delay here.
                 r.restartDelay = mAm.mConstants.SERVICE_RESTART_DURATION;
                 r.nextRestartTime = now + r.restartDelay;
             }
-
         } else {
             // Persistent processes are immediately restarted, so there is no
             // reason to hold of on restarting their services.
             r.totalRestartCount++;
             r.restartCount = 0;
             r.restartDelay = 0;
+            r.mEarliestRestartTime = 0;
             r.nextRestartTime = now;
             reason = "persistent";
         }
 
-        if (!mRestartingServices.contains(r)) {
-            r.createdFromFg = false;
-            mRestartingServices.add(r);
-            r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
+        r.mRestartSchedulingTime = now;
+        if (!inRestarting) {
+            if (oldPosInRestarting == -1) {
+                r.createdFromFg = false;
+                synchronized (mAm.mProcessStats.mLock) {
+                    r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
+                }
+            }
+            boolean added = false;
+            for (int i = 0, size = mRestartingServices.size(); i < size; i++) {
+                final ServiceRecord r2 = mRestartingServices.get(i);
+                if (r2.nextRestartTime > r.nextRestartTime) {
+                    mRestartingServices.add(i, r);
+                    added = true;
+                    break;
+                }
+            }
+            if (!added) {
+                mRestartingServices.add(r);
+            }
         }
 
         cancelForegroundNotificationLocked(r);
 
-        performScheduleRestartLocked(r, "Scheduling", reason, SystemClock.uptimeMillis());
+        performScheduleRestartLocked(r, "Scheduling", reason, now);
 
         return true;
     }
 
-    @VisibleForTesting
     @GuardedBy("mAm")
     void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
             @NonNull String reason, @UptimeMillisLong long now) {
@@ -3596,6 +3695,161 @@
                 r.userId, r.shortInstanceName, r.restartDelay);
     }
 
+    /**
+     * Reschedule service restarts based on the given memory pressure.
+     *
+     * @param prevMemFactor The previous memory factor.
+     * @param curMemFactor The current memory factor.
+     * @param reason The human-readable text about why we're doing rescheduling.
+     * @param now The uptimeMillis
+     */
+    @GuardedBy("mAm")
+    void rescheduleServiceRestartOnMemoryPressureIfNeededLocked(@MemFactor int prevMemFactor,
+            @MemFactor int curMemFactor, @NonNull String reason, @UptimeMillisLong long now) {
+        final boolean enabled = mAm.mConstants.mEnableExtraServiceRestartDelayOnMemPressure;
+        if (!enabled) {
+            return;
+        }
+        performRescheduleServiceRestartOnMemoryPressureLocked(
+                mAm.mConstants.mExtraServiceRestartDelayOnMemPressure[prevMemFactor],
+                mAm.mConstants.mExtraServiceRestartDelayOnMemPressure[curMemFactor], reason, now);
+    }
+
+    /**
+     * Reschedule service restarts based on if the extra delays are enabled or not.
+     *
+     * @param prevEnable The previous state of whether or not it's enabled.
+     * @param curEnabled The current state of whether or not it's enabled.
+     * @param now The uptimeMillis
+     */
+    @GuardedBy("mAm")
+    void rescheduleServiceRestartOnMemoryPressureIfNeededLocked(boolean prevEnabled,
+            boolean curEnabled, @UptimeMillisLong long now) {
+        if (prevEnabled == curEnabled) {
+            return;
+        }
+        final @MemFactor int memFactor = mAm.mAppProfiler.getLastMemoryLevelLocked();
+        final long delay = mAm.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        performRescheduleServiceRestartOnMemoryPressureLocked(prevEnabled ? delay : 0,
+                curEnabled ? delay : 0, "config", now);
+    }
+
+    /**
+     * Rescan the list of pending restarts, reschedule them if needed.
+     *
+     * @param extraRestartTimeBetween The extra interval between restarts.
+     * @param minRestartTimeBetween The minimal interval between restarts.
+     * @param reason The human-readable text about why we're doing rescheduling.
+     * @param now The uptimeMillis
+     */
+    @GuardedBy("mAm")
+    void rescheduleServiceRestartIfPossibleLocked(long extraRestartTimeBetween,
+            long minRestartTimeBetween, @NonNull String reason, @UptimeMillisLong long now) {
+        final long restartTimeBetween = extraRestartTimeBetween + minRestartTimeBetween;
+        final long spanForInsertOne = restartTimeBetween * 2; // Min space to insert a restart.
+
+        long lastRestartTime = now;
+        int lastRestartTimePos = -1; // The list index where the "lastRestartTime" comes from.
+        for (int i = 0, size = mRestartingServices.size(); i < size; i++) {
+            final ServiceRecord r = mRestartingServices.get(i);
+            if ((r.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                    || !isServiceRestartBackoffEnabledLocked(r.packageName)) {
+                lastRestartTime = r.nextRestartTime;
+                lastRestartTimePos = i;
+                continue;
+            }
+            if (lastRestartTime + restartTimeBetween <= r.mEarliestRestartTime) {
+                // Bounded by the earliest restart time, honor it; but we also need to
+                // check if the interval between the earlist and its prior one is enough or not.
+                r.nextRestartTime = Math.max(now, Math.max(r.mEarliestRestartTime, i > 0
+                        ? mRestartingServices.get(i - 1).nextRestartTime + restartTimeBetween
+                        : 0));
+            } else {
+                if (lastRestartTime <= now) {
+                    // It hasn't moved, this is the first one (besides persistent process),
+                    // we don't need to insert the minRestartTimeBetween for it, but need
+                    // the extraRestartTimeBetween still.
+                    r.nextRestartTime = Math.max(now, Math.max(r.mEarliestRestartTime,
+                            r.mRestartSchedulingTime + extraRestartTimeBetween));
+                } else {
+                    r.nextRestartTime = Math.max(now, lastRestartTime + restartTimeBetween);
+                }
+                if (i > lastRestartTimePos + 1) {
+                    // Move the current service record ahead in the list.
+                    mRestartingServices.remove(i);
+                    mRestartingServices.add(lastRestartTimePos + 1, r);
+                }
+            }
+            // Find the next available slot to insert one if there is any
+            for (int j = lastRestartTimePos + 1; j <= i; j++) {
+                final ServiceRecord r2 = mRestartingServices.get(j);
+                final long timeInBetween = r2.nextRestartTime - (j == 0 ? lastRestartTime
+                        : mRestartingServices.get(j - 1).nextRestartTime);
+                if (timeInBetween >= spanForInsertOne) {
+                    break;
+                }
+                lastRestartTime = r2.nextRestartTime;
+                lastRestartTimePos = j;
+            }
+            r.restartDelay = r.nextRestartTime - now;
+            performScheduleRestartLocked(r, "Rescheduling", reason, now);
+        }
+    }
+
+    @GuardedBy("mAm")
+    void performRescheduleServiceRestartOnMemoryPressureLocked(long oldExtraDelay,
+            long newExtraDelay, @NonNull String reason, @UptimeMillisLong long now) {
+        final long delta = newExtraDelay - oldExtraDelay;
+        if (delta == 0) {
+            return;
+        }
+        if (delta > 0) {
+            final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN
+                    + newExtraDelay;
+            long lastRestartTime = now;
+            // Make the delay in between longer.
+            for (int i = 0, size = mRestartingServices.size(); i < size; i++) {
+                final ServiceRecord r = mRestartingServices.get(i);
+                if ((r.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                        || !isServiceRestartBackoffEnabledLocked(r.packageName)) {
+                    lastRestartTime = r.nextRestartTime;
+                    continue;
+                }
+                boolean reschedule = false;
+                if (lastRestartTime <= now) {
+                    // It hasn't moved, this is the first one (besides persistent process),
+                    // we don't need to insert the minRestartTimeBetween for it, but need
+                    // the newExtraDelay still.
+                    final long oldVal = r.nextRestartTime;
+                    r.nextRestartTime = Math.max(now, Math.max(r.mEarliestRestartTime,
+                            r.mRestartSchedulingTime + newExtraDelay));
+                    reschedule = r.nextRestartTime != oldVal;
+                } else if (r.nextRestartTime - lastRestartTime < restartTimeBetween) {
+                    r.nextRestartTime = Math.max(lastRestartTime + restartTimeBetween, now);
+                    reschedule = true;
+                }
+                r.restartDelay = r.nextRestartTime - now;
+                lastRestartTime = r.nextRestartTime;
+                if (reschedule) {
+                    performScheduleRestartLocked(r, "Rescheduling", reason, now);
+                }
+            }
+        } else if (delta < 0) {
+            // Make the delay in between shorter, we'd do a rescan and reschedule.
+            rescheduleServiceRestartIfPossibleLocked(newExtraDelay,
+                    mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN, reason, now);
+        }
+    }
+
+    @GuardedBy("mAm")
+    long getExtraRestartTimeInBetweenLocked() {
+        if (!mAm.mConstants.mEnableExtraServiceRestartDelayOnMemPressure) {
+            return 0;
+        }
+        final @MemFactor int memFactor = mAm.mAppProfiler.getLastMemoryLevelLocked();
+        return mAm.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+    }
+
     final void performServiceRestartLocked(ServiceRecord r) {
         if (!mRestartingServices.contains(r)) {
             return;
@@ -3651,8 +3905,10 @@
                 }
             }
             if (!stillTracking) {
-                r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
-                        SystemClock.uptimeMillis());
+                synchronized (mAm.mProcessStats.mLock) {
+                    r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
+                }
                 r.restartTracker = null;
             }
         }
@@ -3682,6 +3938,9 @@
                         performScheduleRestartLocked(r, "Rescheduling", reason, now);
                     }
                 }
+                // mRestartingServices is sorted by nextRestartTime.
+                Collections.sort(mRestartingServices,
+                        (a, b) -> (int) (a.nextRestartTime - b.nextRestartTime));
             }
         } else {
             removeServiceRestartBackoffEnabledLocked(packageName);
@@ -4172,9 +4431,11 @@
                     + r);
             r.fgRequired = false;
             r.fgWaiting = false;
-            ServiceState stracker = r.getTracker();
-            if (stracker != null) {
-                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+            synchronized (mAm.mProcessStats.mLock) {
+                ServiceState stracker = r.getTracker();
+                if (stracker != null) {
+                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+                }
             }
             mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
@@ -4231,9 +4492,11 @@
         cancelForegroundNotificationLocked(r);
         if (r.isForeground) {
             decActiveForegroundAppLocked(smap, r);
-            ServiceState stracker = r.getTracker();
-            if (stracker != null) {
-                stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+            synchronized (mAm.mProcessStats.mLock) {
+                ServiceState stracker = r.getTracker();
+                if (stracker != null) {
+                    stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+                }
             }
             mAm.mAppOpsService.finishOperation(
                     AppOpsManager.getToken(mAm.mAppOpsService),
@@ -4301,13 +4564,15 @@
            ((ServiceRestarter)r.restarter).setService(null);
         }
 
-        int memFactor = mAm.mProcessStats.getMemFactorLocked();
-        if (r.tracker != null) {
-            r.tracker.setStarted(false, memFactor, now);
-            r.tracker.setBound(false, memFactor, now);
-            if (r.executeNesting == 0) {
-                r.tracker.clearCurrentOwner(r, false);
-                r.tracker = null;
+        synchronized (mAm.mProcessStats.mLock) {
+            final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+            if (r.tracker != null) {
+                r.tracker.setStarted(false, memFactor, now);
+                r.tracker.setBound(false, memFactor, now);
+                if (r.executeNesting == 0) {
+                    r.tracker.clearCurrentOwner(r, false);
+                    r.tracker = null;
+                }
             }
         }
 
@@ -4438,8 +4703,10 @@
                 boolean hasAutoCreate = s.hasAutoCreateConnections();
                 if (!hasAutoCreate) {
                     if (s.tracker != null) {
-                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
-                                SystemClock.uptimeMillis());
+                        synchronized (mAm.mProcessStats.mLock) {
+                            s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
+                                    SystemClock.uptimeMillis());
+                        }
                     }
                 }
                 bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj);
@@ -4531,12 +4798,14 @@
 
     private void serviceProcessGoneLocked(ServiceRecord r, boolean enqueueOomAdj) {
         if (r.tracker != null) {
-            int memFactor = mAm.mProcessStats.getMemFactorLocked();
-            long now = SystemClock.uptimeMillis();
-            r.tracker.setExecuting(false, memFactor, now);
-            r.tracker.setForeground(false, memFactor, now);
-            r.tracker.setBound(false, memFactor, now);
-            r.tracker.setStarted(false, memFactor, now);
+            synchronized (mAm.mProcessStats.mLock) {
+                final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+                final long now = SystemClock.uptimeMillis();
+                r.tracker.setExecuting(false, memFactor, now);
+                r.tracker.setForeground(false, memFactor, now);
+                r.tracker.setBound(false, memFactor, now);
+                r.tracker.setStarted(false, memFactor, now);
+            }
         }
         serviceDoneExecutingLocked(r, true, true, enqueueOomAdj);
     }
@@ -4583,13 +4852,15 @@
             }
             r.executeFg = false;
             if (r.tracker != null) {
-                final int memFactor = mAm.mProcessStats.getMemFactorLocked();
-                final long now = SystemClock.uptimeMillis();
-                r.tracker.setExecuting(false, memFactor, now);
-                r.tracker.setForeground(false, memFactor, now);
-                if (finishing) {
-                    r.tracker.clearCurrentOwner(r, false);
-                    r.tracker = null;
+                synchronized (mAm.mProcessStats.mLock) {
+                    final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+                    final long now = SystemClock.uptimeMillis();
+                    r.tracker.setExecuting(false, memFactor, now);
+                    r.tracker.setForeground(false, memFactor, now);
+                    if (finishing) {
+                        r.tracker.clearCurrentOwner(r, false);
+                        r.tracker = null;
+                    }
                 }
             }
             if (finishing) {
@@ -4604,6 +4875,11 @@
     boolean attachApplicationLocked(ProcessRecord proc, String processName)
             throws RemoteException {
         boolean didSomething = false;
+
+        // Update the app background restriction of the caller
+        proc.mState.setBackgroundRestricted(appRestrictedAnyInBackground(
+                proc.uid, proc.info.packageName));
+
         // Collect any services that are waiting for this process to come up.
         if (mPendingServices.size() > 0) {
             ServiceRecord sr = null;
@@ -4647,6 +4923,7 @@
         // run at this point just because their restart time hasn't come up.
         if (mRestartingServices.size() > 0) {
             ServiceRecord sr;
+            boolean didImmediateRestart = false;
             for (int i=0; i<mRestartingServices.size(); i++) {
                 sr = mRestartingServices.get(i);
                 if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
@@ -4655,6 +4932,18 @@
                 }
                 mAm.mHandler.removeCallbacks(sr.restarter);
                 mAm.mHandler.post(sr.restarter);
+                didImmediateRestart = true;
+            }
+            if (didImmediateRestart) {
+                // Since we kicked off all its pending restarts, there could be some open slots
+                // in the pending restarts list, schedule a check on it. We are posting to the same
+                // handler, so by the time of the check, those immediate restarts should be done.
+                mAm.mHandler.post(() ->
+                        rescheduleServiceRestartIfPossibleLocked(
+                                getExtraRestartTimeInBetweenLocked(),
+                                mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN,
+                                "other", SystemClock.uptimeMillis())
+                );
             }
         }
         return didSomething;
@@ -4974,8 +5263,10 @@
                     // down it.
                     sr.startRequested = false;
                     if (sr.tracker != null) {
-                        sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
-                                SystemClock.uptimeMillis());
+                        synchronized (mAm.mProcessStats.mLock) {
+                            sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+                                    SystemClock.uptimeMillis());
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index ac0a198..eb37e2d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -21,6 +21,7 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 
+import android.annotation.NonNull;
 import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -31,6 +32,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PowerExemptionManager;
+import android.os.SystemClock;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.OnPropertiesChangedListener;
 import android.provider.DeviceConfig.Properties;
@@ -40,6 +42,8 @@
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
@@ -109,6 +113,10 @@
     static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
     static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
     static final String KEY_FGS_ALLOW_OPT_OUT = "fgs_allow_opt_out";
+    static final String KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE =
+            "extra_delay_svc_restart_mem_pressure";
+    static final String KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE =
+            "enable_extra_delay_svc_restart_mem_pressure";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -159,6 +167,25 @@
             DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = 1;
     private static final boolean DEFAULT_FGS_ALLOW_OPT_OUT = false;
 
+    /**
+     * The extra delays we're putting to service restarts, based on current memory pressure.
+     */
+    private static final long DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_NORMAL_MEM = 0; // ms
+    private static final long DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MODERATE_MEM = 10000; // ms
+    private static final long DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_LOW_MEM = 20000; // ms
+    private static final long DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_CRITICAL_MEM = 30000; // ms
+    private static final long[] DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE  = {
+        DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_NORMAL_MEM,
+        DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MODERATE_MEM,
+        DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_LOW_MEM,
+        DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_CRITICAL_MEM,
+    };
+
+    /**
+     * Whether or not to enable the extra delays to service restarts on memory pressure.
+     */
+    private static final boolean DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = true;
+
     // Flag stored in the DeviceConfig API.
     /**
      * Maximum number of cached processes.
@@ -501,6 +528,20 @@
      */
     volatile boolean mFgsAllowOptOut = DEFAULT_FGS_ALLOW_OPT_OUT;
 
+    /*
+     * The extra delays we're putting to service restarts, based on current memory pressure.
+     */
+    @GuardedBy("mService")
+    long[] mExtraServiceRestartDelayOnMemPressure =
+            DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
+
+    /**
+     * Whether or not to enable the extra delays to service restarts on memory pressure.
+     */
+    @GuardedBy("mService")
+    boolean mEnableExtraServiceRestartDelayOnMemPressure =
+            DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
+
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -714,6 +755,12 @@
                             case KEY_FGS_ALLOW_OPT_OUT:
                                 updateFgsAllowOptOut();
                                 break;
+                            case KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
+                                updateExtraServiceRestartDelayOnMemPressure();
+                                break;
+                            case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
+                                updateEnableExtraServiceRestartDelayOnMemPressure();
+                                break;
                             default:
                                 break;
                         }
@@ -1064,6 +1111,51 @@
                 DEFAULT_FGS_ALLOW_OPT_OUT);
     }
 
+    private void updateExtraServiceRestartDelayOnMemPressure() {
+        synchronized (mService) {
+            final int memFactor = mService.mAppProfiler.getLastMemoryLevelLocked();
+            final long[] prevDelays = mExtraServiceRestartDelayOnMemPressure;
+            mExtraServiceRestartDelayOnMemPressure = parseLongArray(
+                    KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE,
+                    DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE);
+            mService.mServices.performRescheduleServiceRestartOnMemoryPressureLocked(
+                    mExtraServiceRestartDelayOnMemPressure[memFactor],
+                    prevDelays[memFactor], "config", SystemClock.uptimeMillis());
+        }
+    }
+
+    private void updateEnableExtraServiceRestartDelayOnMemPressure() {
+        synchronized (mService) {
+            final boolean prevEnabled = mEnableExtraServiceRestartDelayOnMemPressure;
+            mEnableExtraServiceRestartDelayOnMemPressure = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE,
+                    DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE);
+            mService.mServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                    prevEnabled, mEnableExtraServiceRestartDelayOnMemPressure,
+                    SystemClock.uptimeMillis());
+        }
+    }
+
+    private long[] parseLongArray(@NonNull String key, @NonNull long[] def) {
+        final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                key, null);
+        if (!TextUtils.isEmpty(val)) {
+            final String[] ss = val.split(",");
+            if (ss.length == def.length) {
+                final long[] tmp = new long[ss.length];
+                try {
+                    for (int i = 0; i < ss.length; i++) {
+                        tmp[i] = Long.parseLong(ss[i]);
+                    }
+                    return tmp;
+                } catch (NumberFormatException e) {
+                }
+            }
+        }
+        return def;
+    }
+
     private void updateImperceptibleKillExemptions() {
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7fd7e19..cdfc795 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1831,6 +1831,18 @@
                     }
                 });
 
+        mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
+                new IAppOpsCallback.Stub() {
+                    @Override public void opChanged(int op, int uid, String packageName) {
+                        if (op == AppOpsManager.OP_RUN_ANY_IN_BACKGROUND && packageName != null) {
+                            synchronized (ActivityManagerService.this) {
+                                mServices.updateAppRestrictedAnyInBackgroundLocked(
+                                        uid, packageName);
+                            }
+                        }
+                    }
+                });
+
         final int[] cameraOp = {AppOpsManager.OP_CAMERA};
         mAppOpsService.startWatchingActive(cameraOp, new IAppOpsActiveCallback.Stub() {
             @Override
@@ -5707,7 +5719,7 @@
 
     @Override
     public int[] checkUriPermissions(@NonNull List<Uri> uris, int pid, int uid,
-            final int modeFlags, IBinder callerToken) {
+            final int modeFlags, int userId, IBinder callerToken) {
         final int size = uris.size();
         int[] res = new int[size];
         // Default value DENIED.
@@ -5715,9 +5727,9 @@
 
         for (int i = 0; i < size; i++) {
             final Uri uri = uris.get(i);
-            final int userId = ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+            final int userIdFromUri = ContentProvider.getUserIdFromUri(uri, userId);
             res[i] = checkUriPermission(ContentProvider.getUriWithoutUserId(uri), pid, uid,
-                    modeFlags, userId, callerToken);
+                    modeFlags, userIdFromUri, callerToken);
         }
         return res;
     }
@@ -12628,76 +12640,72 @@
         int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
 
         List<ResolveInfo> receivers = null;
-        try {
-            HashSet<ComponentName> singleUserReceivers = null;
-            boolean scannedFirstReceivers = false;
-            for (int user : users) {
-                // Skip users that have Shell restrictions
-                if (callingUid == SHELL_UID
-                        && mUserController.hasUserRestriction(
-                                UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
-                    continue;
-                }
-                List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
-                        .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
-                if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
-                    // If this is not the system user, we need to check for
-                    // any receivers that should be filtered out.
-                    for (int i=0; i<newReceivers.size(); i++) {
-                        ResolveInfo ri = newReceivers.get(i);
-                        if ((ri.activityInfo.flags&ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
-                            newReceivers.remove(i);
-                            i--;
-                        }
+        HashSet<ComponentName> singleUserReceivers = null;
+        boolean scannedFirstReceivers = false;
+        for (int user : users) {
+            // Skip users that have Shell restrictions
+            if (callingUid == SHELL_UID
+                    && mUserController.hasUserRestriction(
+                    UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
+                continue;
+            }
+            List<ResolveInfo> newReceivers = mPackageManagerInt
+                    .queryIntentReceivers(intent, resolvedType, pmFlags, callingUid, user);
+            if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
+                // If this is not the system user, we need to check for
+                // any receivers that should be filtered out.
+                for (int i = 0; i < newReceivers.size(); i++) {
+                    ResolveInfo ri = newReceivers.get(i);
+                    if ((ri.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
+                        newReceivers.remove(i);
+                        i--;
                     }
                 }
-                if (newReceivers != null && newReceivers.size() == 0) {
-                    newReceivers = null;
-                }
-                if (receivers == null) {
-                    receivers = newReceivers;
-                } else if (newReceivers != null) {
-                    // We need to concatenate the additional receivers
-                    // found with what we have do far.  This would be easy,
-                    // but we also need to de-dup any receivers that are
-                    // singleUser.
-                    if (!scannedFirstReceivers) {
-                        // Collect any single user receivers we had already retrieved.
-                        scannedFirstReceivers = true;
-                        for (int i=0; i<receivers.size(); i++) {
-                            ResolveInfo ri = receivers.get(i);
-                            if ((ri.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
-                                ComponentName cn = new ComponentName(
-                                        ri.activityInfo.packageName, ri.activityInfo.name);
-                                if (singleUserReceivers == null) {
-                                    singleUserReceivers = new HashSet<ComponentName>();
-                                }
-                                singleUserReceivers.add(cn);
-                            }
-                        }
-                    }
-                    // Add the new results to the existing results, tracking
-                    // and de-dupping single user receivers.
-                    for (int i=0; i<newReceivers.size(); i++) {
-                        ResolveInfo ri = newReceivers.get(i);
+            }
+            if (newReceivers != null && newReceivers.size() == 0) {
+                newReceivers = null;
+            }
+            if (receivers == null) {
+                receivers = newReceivers;
+            } else if (newReceivers != null) {
+                // We need to concatenate the additional receivers
+                // found with what we have do far.  This would be easy,
+                // but we also need to de-dup any receivers that are
+                // singleUser.
+                if (!scannedFirstReceivers) {
+                    // Collect any single user receivers we had already retrieved.
+                    scannedFirstReceivers = true;
+                    for (int i = 0; i < receivers.size(); i++) {
+                        ResolveInfo ri = receivers.get(i);
                         if ((ri.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
                             ComponentName cn = new ComponentName(
                                     ri.activityInfo.packageName, ri.activityInfo.name);
                             if (singleUserReceivers == null) {
                                 singleUserReceivers = new HashSet<ComponentName>();
                             }
-                            if (!singleUserReceivers.contains(cn)) {
-                                singleUserReceivers.add(cn);
-                                receivers.add(ri);
-                            }
-                        } else {
-                            receivers.add(ri);
+                            singleUserReceivers.add(cn);
                         }
                     }
                 }
+                // Add the new results to the existing results, tracking
+                // and de-dupping single user receivers.
+                for (int i = 0; i < newReceivers.size(); i++) {
+                    ResolveInfo ri = newReceivers.get(i);
+                    if ((ri.activityInfo.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                        ComponentName cn = new ComponentName(
+                                ri.activityInfo.packageName, ri.activityInfo.name);
+                        if (singleUserReceivers == null) {
+                            singleUserReceivers = new HashSet<ComponentName>();
+                        }
+                        if (!singleUserReceivers.contains(cn)) {
+                            singleUserReceivers.add(cn);
+                            receivers.add(ri);
+                        }
+                    } else {
+                        receivers.add(ri);
+                    }
+                }
             }
-        } catch (RemoteException ex) {
-            // pm is in same process, this will never happen.
         }
         if (receivers != null && broadcastAllowList != null) {
             for (int i = receivers.size() - 1; i >= 0; i--) {
@@ -13331,8 +13339,7 @@
         List receivers = null;
         List<BroadcastFilter> registeredReceivers = null;
         // Need to resolve the intent to interested receivers...
-        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                 == 0) {
+        if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
             receivers = collectReceiverComponents(
                     intent, resolvedType, callingUid, users, broadcastAllowList);
         }
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 36c0de9..9982922 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -393,6 +393,7 @@
         static final int COLLECT_PSS_BG_MSG = 1;
         static final int DEFER_PSS_MSG = 2;
         static final int STOP_DEFERRING_PSS_MSG = 3;
+        static final int MEMORY_PRESSURE_CHANGED = 4;
         BgHandler(Looper looper) {
             super(looper);
         }
@@ -409,6 +410,11 @@
                 case STOP_DEFERRING_PSS_MSG:
                     stopDeferPss();
                     break;
+                case MEMORY_PRESSURE_CHANGED:
+                    synchronized (mService) {
+                        handleMemoryPressureChangedLocked(msg.arg1, msg.arg2);
+                    }
+                    break;
             }
         }
     }
@@ -912,12 +918,18 @@
     }
 
     @GuardedBy("mService")
-    int getLastMemoryLevelLocked() {
+    @MemFactor int getLastMemoryLevelLocked() {
+        if (mMemFactorOverride != ADJ_MEM_FACTOR_NOTHING) {
+            return mMemFactorOverride;
+        }
         return mLastMemoryLevel;
     }
 
     @GuardedBy("mService")
     boolean isLastMemoryLevelNormal() {
+        if (mMemFactorOverride != ADJ_MEM_FACTOR_NOTHING) {
+            return mMemFactorOverride <= ADJ_MEM_FACTOR_NORMAL;
+        }
         return mLastMemoryLevel <= ADJ_MEM_FACTOR_NORMAL;
     }
 
@@ -989,6 +1001,8 @@
         if (memFactor != mLastMemoryLevel) {
             EventLogTags.writeAmMemFactor(memFactor, mLastMemoryLevel);
             FrameworkStatsLog.write(FrameworkStatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor);
+            mBgHandler.obtainMessage(BgHandler.MEMORY_PRESSURE_CHANGED, mLastMemoryLevel, memFactor)
+                    .sendToTarget();
         }
         mLastMemoryLevel = memFactor;
         mLastNumProcesses = mService.mProcessList.getLruSizeLOSP();
@@ -1636,6 +1650,13 @@
         }
     }
 
+    @GuardedBy("mService")
+    private void handleMemoryPressureChangedLocked(@MemFactor int oldMemFactor,
+            @MemFactor int newMemFactor) {
+        mService.mServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                oldMemFactor, newMemFactor, "mem-pressure-event", SystemClock.uptimeMillis());
+    }
+
     @GuardedBy("mProfilerLock")
     private void stopProfilerLPf(ProcessRecord proc, int profileType) {
         if (proc == null || proc == mProfileData.getProfileProc()) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 399a245..60530a3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -841,6 +841,12 @@
 
     public void noteEvent(final int code, final String name, final int uid) {
         enforceCallingPermission();
+        if (name == null) {
+            // TODO(b/194733136): Replace with an IllegalArgumentException throw.
+            Slog.wtfStack(TAG, "noteEvent called with null name. code = " + code);
+            return;
+        }
+
         synchronized (mLock) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9dbb707..f32aa22 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.ProcLocksReader;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.ServiceThread;
 
@@ -100,7 +101,7 @@
 
     // Defaults for phenotype flags.
     @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
-    @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = false;
+    @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
     @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE;
     @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL;
     @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
@@ -275,7 +276,7 @@
             DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ;
     @GuardedBy("mPhenotypeFlagLock")
     private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
-    private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
+    private volatile boolean mUseFreezer = false; // set to DEFAULT in init()
     @GuardedBy("this")
     private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
     private final Random mRandom = new Random();
@@ -319,6 +320,7 @@
     private int mPersistentCompactionCount;
     private int mBfgsCompactionCount;
     private final ProcessDependencies mProcessDependencies;
+    private final ProcLocksReader mProcLocksReader;
 
     public CachedAppOptimizer(ActivityManagerService am) {
         this(am, null, new DefaultProcessDependencies());
@@ -335,6 +337,7 @@
         mProcessDependencies = processDependencies;
         mTestCallback = callback;
         mSettingsObserver = new SettingsContentObserver();
+        mProcLocksReader = new ProcLocksReader();
     }
 
     /**
@@ -675,6 +678,8 @@
                     KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
             mUseFreezer = isFreezerSupported();
             updateFreezerDebounceTimeout();
+        } else {
+            mUseFreezer = false;
         }
 
         final boolean useFreezer = mUseFreezer;
@@ -1312,7 +1317,7 @@
 
             try {
                 // pre-check for locks to avoid unnecessary freeze/unfreeze operations
-                if (Process.hasFileLocks(pid)) {
+                if (mProcLocksReader.hasFileLocks(pid)) {
                     if (DEBUG_FREEZER) {
                         Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
                     }
@@ -1399,7 +1404,7 @@
 
             try {
                 // post-check to prevent races
-                if (Process.hasFileLocks(pid)) {
+                if (mProcLocksReader.hasFileLocks(pid)) {
                     if (DEBUG_FREEZER) {
                         Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
                     }
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index e6cd509..9161271 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -47,6 +47,7 @@
     public AssociationState.SourceState association; // Association tracking
     String stringName;              // Caching of toString.
     boolean serviceDead;            // Well is it?
+    private Object mProcStatsLock;  // Internal lock for accessing AssociationState
 
     // Please keep the following two enum list synced.
     private static final int[] BIND_ORIG_ENUMS = new int[] {
@@ -137,23 +138,29 @@
                 Slog.wtf(TAG_AM, "Inactive holder in referenced service "
                         + binding.service.shortInstanceName + ": proc=" + binding.service.app);
             } else {
-                association = holder.pkg.getAssociationStateLocked(holder.state,
-                        binding.service.instanceName.getClassName()).startSource(clientUid,
-                        clientProcessName, clientPackageName);
-
+                mProcStatsLock = binding.service.app.mService.mProcessStats.mLock;
+                synchronized (mProcStatsLock) {
+                    association = holder.pkg.getAssociationStateLocked(holder.state,
+                            binding.service.instanceName.getClassName()).startSource(clientUid,
+                            clientProcessName, clientPackageName);
+                }
             }
         }
     }
 
     public void trackProcState(int procState, int seq, long now) {
         if (association != null) {
-            association.trackProcState(procState, seq, now);
+            synchronized (mProcStatsLock) {
+                association.trackProcState(procState, seq, now);
+            }
         }
     }
 
     public void stopAssociation() {
         if (association != null) {
-            association.stop();
+            synchronized (mProcStatsLock) {
+                association.stop();
+            }
             association = null;
         }
     }
diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
index 3bc4fcf..3b9d47d 100644
--- a/services/core/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/core/java/com/android/server/am/ContentProviderConnection.java
@@ -38,6 +38,7 @@
     public final String clientPackage;
     public AssociationState.SourceState association;
     public final long createTime;
+    private Object mProcStatsLock;  // Internal lock for accessing AssociationState
 
     /**
      * Internal lock that guards access to the two counters.
@@ -87,23 +88,29 @@
                 Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
                         + provider.name.toShortString() + ": proc=" + provider.proc);
             } else {
-                association = holder.pkg.getAssociationStateLocked(holder.state,
-                        provider.name.getClassName()).startSource(client.uid, client.processName,
-                        clientPackage);
-
+                mProcStatsLock = provider.proc.mService.mProcessStats.mLock;
+                synchronized (mProcStatsLock) {
+                    association = holder.pkg.getAssociationStateLocked(holder.state,
+                            provider.name.getClassName()).startSource(client.uid,
+                            client.processName, clientPackage);
+                }
             }
         }
     }
 
     public void trackProcState(int procState, int seq, long now) {
         if (association != null) {
-            association.trackProcState(procState, seq, now);
+            synchronized (mProcStatsLock) {
+                association.trackProcState(procState, seq, now);
+            }
         }
     }
 
     public void stopAssociation() {
         if (association != null) {
-            association.stop();
+            synchronized (mProcStatsLock) {
+                association.stop();
+            }
             association = null;
         }
     }
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index 5fd15db..75f31c0 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -321,6 +321,7 @@
         final String mOwningProcessName;
         int mAcquisitionCount;
         AssociationState.SourceState mAssociation;
+        private Object mProcStatsLock;  // Internal lock for accessing AssociationState
 
         public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) {
             mToken = token;
@@ -353,17 +354,21 @@
                     Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
                             + provider.name.toShortString() + ": proc=" + provider.proc);
                 } else {
-                    mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
-                            provider.name.getClassName()).startSource(mOwningUid,
-                            mOwningProcessName, null);
-
+                    mProcStatsLock = provider.proc.mService.mProcessStats.mLock;
+                    synchronized (mProcStatsLock) {
+                        mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
+                                provider.name.getClassName()).startSource(mOwningUid,
+                                mOwningProcessName, null);
+                    }
                 }
             }
         }
 
         public void stopAssociation() {
             if (mAssociation != null) {
-                mAssociation.stop();
+                synchronized (mProcStatsLock) {
+                    mAssociation.stop();
+                }
                 mAssociation = null;
             }
         }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 93d5c06b..27d8119 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -511,6 +511,7 @@
         }
 
         app.mState.resetCachedInfo();
+        app.mState.setCurBoundByNonBgRestrictedApp(false);
         UidRecord uidRec = app.getUidRecord();
         if (uidRec != null) {
             if (DEBUG_UID_OBSERVERS) {
@@ -644,6 +645,7 @@
         state.setContainsCycle(false);
         state.setProcStateChanged(false);
         state.resetCachedInfo();
+        state.setCurBoundByNonBgRestrictedApp(false);
         // Check if this process is in the pending list too, remove from pending list if so.
         mPendingProcessSet.remove(app);
         boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
@@ -934,6 +936,7 @@
                 state.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
                 state.setSetCapability(PROCESS_CAPABILITY_NONE);
                 state.resetCachedInfo();
+                state.setCurBoundByNonBgRestrictedApp(false);
             }
         }
         mProcessesInCycle.clear();
@@ -1900,6 +1903,7 @@
         }
 
         int capabilityFromFGS = 0; // capability from foreground service.
+        boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp();
         boolean scheduleLikeTopApp = false;
         for (int is = psr.numberOfRunningServices() - 1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -2014,6 +2018,11 @@
 
                     final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
 
+                    boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
+                            || clientProcState <= PROCESS_STATE_BOUND_TOP
+                            || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+                                    && !cstate.isBackgroundRestricted());
+
                     if (client.mOptRecord.shouldNotFreeze()) {
                         // Propagate the shouldNotFreeze flag down the bindings.
                         app.mOptRecord.setShouldNotFreeze(true);
@@ -2336,6 +2345,12 @@
                     // Propagate the shouldNotFreeze flag down the bindings.
                     app.mOptRecord.setShouldNotFreeze(true);
                 }
+
+                boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
+                        || clientProcState <= PROCESS_STATE_BOUND_TOP
+                        || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+                                && !cstate.isBackgroundRestricted());
+
                 String adjType = null;
                 if (adj > clientAdj) {
                     if (state.hasShownUi() && !state.getCachedIsHomeProcess()
@@ -2513,6 +2528,7 @@
         state.updateLastInvisibleTime(hasVisibleActivities);
         state.setHasForegroundActivities(foregroundActivities);
         state.setCompletedAdjSeq(mAdjSeq);
+        state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);
 
         // if curAdj or curProcState improved, then this process was promoted
         return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
@@ -2820,8 +2836,10 @@
                 state.setNotCachedSinceIdle(false);
             }
             if (!doingAll) {
-                mService.setProcessTrackerStateLOSP(app,
-                        mService.mProcessStats.getMemFactorLocked(), now);
+                synchronized (mService.mProcessStats.mLock) {
+                    mService.setProcessTrackerStateLOSP(app,
+                            mService.mProcessStats.getMemFactorLocked(), now);
+                }
             } else {
                 state.setProcStateChanged(true);
             }
@@ -2853,6 +2871,19 @@
             state.setSetCapability(state.getCurCapability());
         }
 
+        final boolean curBoundByNonBgRestrictedApp = state.isCurBoundByNonBgRestrictedApp();
+        if (curBoundByNonBgRestrictedApp != state.isSetBoundByNonBgRestrictedApp()) {
+            state.setSetBoundByNonBgRestrictedApp(curBoundByNonBgRestrictedApp);
+            if (!curBoundByNonBgRestrictedApp && state.isBackgroundRestricted()) {
+                mService.mHandler.post(() -> {
+                    synchronized (mService) {
+                        mService.mServices.stopAllForegroundServicesLocked(
+                                app.uid, app.info.packageName);
+                    }
+                });
+            }
+        }
+
         if (changes != 0) {
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Changes in " + app + ": " + changes);
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index ca31681..b07684c 100644
--- a/services/core/java/com/android/server/am/PhantomProcessList.java
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -365,6 +365,9 @@
     private int onPhantomProcessFdEvent(FileDescriptor fd, int events) {
         synchronized (mLock) {
             final PhantomProcessRecord proc = mPhantomProcessesPidFds.get(fd.getInt$());
+            if (proc == null) {
+                return 0;
+            }
             if ((events & EVENT_INPUT) != 0) {
                 proc.onProcDied(true);
             } else {
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index dc6bcd8..85d06c3 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -302,6 +302,23 @@
     private int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
 
     /**
+     * Whether or not the app is background restricted (OP_RUN_ANY_IN_BACKGROUND is NOT allowed).
+     */
+    @GuardedBy("mService")
+    private boolean mBackgroundRestricted = false;
+
+    /**
+     * Whether or not this process is being bound by a non-background restricted app.
+     */
+    @GuardedBy("mService")
+    private boolean mCurBoundByNonBgRestrictedApp = false;
+
+    /**
+     * Last set state of {@link #mCurBoundByNonBgRestrictedApp}.
+     */
+    private boolean mSetBoundByNonBgRestrictedApp = false;
+
+    /**
      * Debugging: primary thing impacting oom_adj.
      */
     @GuardedBy("mService")
@@ -1113,6 +1130,36 @@
     }
 
     @GuardedBy("mService")
+    boolean isBackgroundRestricted() {
+        return mBackgroundRestricted;
+    }
+
+    @GuardedBy("mService")
+    void setBackgroundRestricted(boolean restricted) {
+        mBackgroundRestricted = restricted;
+    }
+
+    @GuardedBy("mService")
+    boolean isCurBoundByNonBgRestrictedApp() {
+        return mCurBoundByNonBgRestrictedApp;
+    }
+
+    @GuardedBy("mService")
+    void setCurBoundByNonBgRestrictedApp(boolean bound) {
+        mCurBoundByNonBgRestrictedApp = bound;
+    }
+
+    @GuardedBy("mService")
+    boolean isSetBoundByNonBgRestrictedApp() {
+        return mSetBoundByNonBgRestrictedApp;
+    }
+
+    @GuardedBy("mService")
+    void setSetBoundByNonBgRestrictedApp(boolean bound) {
+        mSetBoundByNonBgRestrictedApp = bound;
+    }
+
+    @GuardedBy("mService")
     void updateLastInvisibleTime(boolean hasVisibleActivities) {
         if (hasVisibleActivities) {
             mLastInvisibleTime = Long.MAX_VALUE;
@@ -1164,7 +1211,14 @@
         ActivityManager.printCapabilitiesFull(pw, mSetCapability);
         pw.println();
         pw.print(prefix); pw.print("allowStartFgsState=");
-        pw.println(mAllowStartFgsState);
+        pw.print(mAllowStartFgsState);
+        if (mBackgroundRestricted) {
+            pw.print(" backgroundRestricted=");
+            pw.print(mBackgroundRestricted);
+            pw.print(" boundByNonBgRestrictedApp=");
+            pw.print(mSetBoundByNonBgRestrictedApp);
+        }
+        pw.println();
         if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
             pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 804e442..97ed0a38 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -196,6 +196,22 @@
 
     boolean mKeepWarming; // Whether or not it'll keep critical code path of the host warm
 
+    /**
+     * The original earliest restart time, which considers the number of crashes, etc.,
+     * but doesn't include the extra delays we put in between to scatter the restarts;
+     * it's the earliest time this auto service restart could happen alone(except those
+     * batch restarts which happens at time of process attach).
+     */
+    long mEarliestRestartTime;
+
+    /**
+     * The original time when the service start is scheduled, it does NOT include the reschedules.
+     *
+     * <p>The {@link #restartDelay} would be updated when its restart is rescheduled, but this field
+     * won't, so it could be used when dumping how long the restart is delayed actually.</p>
+     */
+    long mRestartSchedulingTime;
+
     static class StartItem {
         final ServiceRecord sr;
         final boolean taskRemoved;
@@ -373,10 +389,12 @@
         if (destroying || destroyTime != 0) {
             ProtoUtils.toDuration(proto, ServiceRecordProto.DESTORY_TIME, destroyTime, now);
         }
-        if (crashCount != 0 || restartCount != 0 || restartDelay != 0 || nextRestartTime != 0) {
+        if (crashCount != 0 || restartCount != 0 || (nextRestartTime - mRestartSchedulingTime) != 0
+                || nextRestartTime != 0) {
             long crashToken = proto.start(ServiceRecordProto.CRASH);
             proto.write(ServiceRecordProto.Crash.RESTART_COUNT, restartCount);
-            ProtoUtils.toDuration(proto, ServiceRecordProto.Crash.RESTART_DELAY, restartDelay, now);
+            ProtoUtils.toDuration(proto, ServiceRecordProto.Crash.RESTART_DELAY,
+                    (nextRestartTime - mRestartSchedulingTime), now);
             ProtoUtils.toDuration(proto,
                     ServiceRecordProto.Crash.NEXT_RESTART_TIME, nextRestartTime, now);
             proto.write(ServiceRecordProto.Crash.CRASH_COUNT, crashCount);
@@ -504,10 +522,10 @@
                     pw.println();
         }
         if (crashCount != 0 || restartCount != 0
-                || restartDelay != 0 || nextRestartTime != 0) {
+                || (nextRestartTime - mRestartSchedulingTime) != 0 || nextRestartTime != 0) {
             pw.print(prefix); pw.print("restartCount="); pw.print(restartCount);
                     pw.print(" restartDelay=");
-                    TimeUtils.formatDuration(restartDelay, now, pw);
+                    TimeUtils.formatDuration(nextRestartTime - mRestartSchedulingTime, now, pw);
                     pw.print(" nextRestartTime=");
                     TimeUtils.formatDuration(nextRestartTime, now, pw);
                     pw.print(" crashCount="); pw.println(crashCount);
@@ -899,6 +917,8 @@
         restartCount = 0;
         restartDelay = 0;
         restartTime = 0;
+        mEarliestRestartTime  = 0;
+        mRestartSchedulingTime = 0;
     }
 
     public StartItem findDeliveredStart(int id, boolean taskRemoved, boolean remove) {
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c103344..fc02f19 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -84,6 +84,7 @@
         DeviceConfig.NAMESPACE_CONNECTIVITY,
         DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
+        DeviceConfig.NAMESPACE_LMKD_NATIVE,
         DeviceConfig.NAMESPACE_MEDIA_NATIVE,
         DeviceConfig.NAMESPACE_NETD_NATIVE,
         DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 4ba59fa..6101e26 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -282,6 +283,17 @@
         }
     }
 
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    ProcessRecord getProcessInPackage(String packageName) {
+        for (int i = mProcRecords.size() - 1; i >= 0; i--) {
+            final ProcessRecord app = mProcRecords.valueAt(i);
+            if (app != null && TextUtils.equals(app.info.packageName, packageName)) {
+                return app;
+            }
+        }
+        return null;
+    }
+
     @GuardedBy({"mService", "mProcLock"})
     void addProcess(ProcessRecord app) {
         mProcRecords.add(app);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index ca844f5..cfd2978 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -45,6 +45,9 @@
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
 import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.RestrictionBypass;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
@@ -1238,6 +1241,11 @@
                     scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName,
                             tag, true, event.getAttributionFlags(), event.getAttributionChainId());
                 }
+                // Note: this always sends MODE_ALLOWED, even if the mode is FOREGROUND
+                // TODO ntmyren: figure out how to get the real mode.
+                scheduleOpStartedIfNeededLocked(parent.op, parent.uid, parent.packageName,
+                        tag, event.getFlags(), MODE_ALLOWED, START_TYPE_RESUMED,
+                        event.getAttributionFlags(), event.getAttributionChainId());
             }
             mPausedInProgressEvents = null;
         }
@@ -3438,7 +3446,7 @@
                         + " package " + packageName + "flags: " +
                         AppOpsManager.flagsToString(flags));
                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                        packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                        packageName);
             }
             final Op op = getOpLocked(ops, code, uid, true);
             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
@@ -3945,13 +3953,15 @@
         }
 
         boolean isRestricted = false;
+        int startType = START_TYPE_FAILED;
         synchronized (this) {
             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
             if (ops == null) {
                 if (!dryRun) {
                     scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                            flags, AppOpsManager.MODE_IGNORED);
+                            flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
+                            attributionChainId);
                 }
                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName + " flags: "
@@ -3977,7 +3987,7 @@
                     if (!dryRun) {
                         attributedOp.rejected(uidState.state, flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, uidMode);
+                                flags, uidMode, startType, attributionFlags, attributionChainId);
                     }
                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
                 }
@@ -3993,7 +4003,7 @@
                     if (!dryRun) {
                         attributedOp.rejected(uidState.state, flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, mode);
+                                flags, mode, startType, attributionFlags, attributionChainId);
                     }
                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
                 }
@@ -4011,12 +4021,14 @@
                         attributedOp.started(clientId, proxyUid, proxyPackageName,
                                 proxyAttributionTag, uidState.state, flags, attributionFlags,
                                 attributionChainId);
+                        startType = START_TYPE_STARTED;
                     }
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
                 scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        isRestricted ? MODE_IGNORED : MODE_ALLOWED);
+                        isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
+                        attributionChainId);
             }
         }
 
@@ -4187,7 +4199,9 @@
     }
 
     private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
-            String attributionTag, @OpFlags int flags, @Mode int result) {
+            String attributionTag, @OpFlags int flags, @Mode int result,
+            @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
         ArraySet<StartedCallback> dispatchedCallbacks = null;
         final int callbackListCount = mStartedWatchers.size();
         for (int i = 0; i < callbackListCount; i++) {
@@ -4213,12 +4227,13 @@
         mHandler.sendMessage(PooledLambda.obtainMessage(
                 AppOpsService::notifyOpStarted,
                 this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
-                result));
+                result, startedType, attributionFlags, attributionChainId));
     }
 
     private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
-            @Mode int result) {
+            @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             final int callbackCount = callbacks.size();
@@ -4226,7 +4241,7 @@
                 final StartedCallback callback = callbacks.valueAt(i);
                 try {
                     callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
-                            result);
+                            result, startedType, attributionFlags, attributionChainId);
                 } catch (RemoteException e) {
                     /* do nothing */
                 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index fcd198e..2f69abf 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -738,6 +738,11 @@
     private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
     private long mLoweredFromNormalToVibrateTime;
 
+    // Uid of the active hotword detection service to check if caller is the one or not.
+    @GuardedBy("mHotwordDetectionServiceUidLock")
+    private int mHotwordDetectionServiceUid = android.os.Process.INVALID_UID;
+    private final Object mHotwordDetectionServiceUidLock = new Object();
+
     // Array of Uids of valid accessibility services to check if caller is one of them
     private final Object mAccessibilityServiceUidsLock = new Object();
     @GuardedBy("mAccessibilityServiceUidsLock")
@@ -1339,6 +1344,9 @@
             updateAssistantUId(true);
             AudioSystem.setRttEnabled(mRttEnabled);
         }
+        synchronized (mHotwordDetectionServiceUidLock) {
+            AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+        }
         synchronized (mAccessibilityServiceUidsLock) {
             AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
         }
@@ -9082,6 +9090,16 @@
         }
 
         @Override
+        public void setHotwordDetectionServiceUid(int uid) {
+            synchronized (mHotwordDetectionServiceUidLock) {
+                if (mHotwordDetectionServiceUid != uid) {
+                    mHotwordDetectionServiceUid = uid;
+                    AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+                }
+            }
+        }
+
+        @Override
         public void setAccessibilityServiceUids(IntArray uids) {
             synchronized (mAccessibilityServiceUidsLock) {
                 if (uids.size() == 0) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 973fbd2..6d56780 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -367,6 +367,14 @@
     }
 
     /**
+     * Same as {@link AudioSystem#setHotwordDetectionServiceUid(int)}
+     * Communicate UID of current HotwordDetectionService to audio policy service.
+     */
+    public int setHotwordDetectionServiceUid(int uid) {
+        return AudioSystem.setHotwordDetectionServiceUid(uid);
+    }
+
+    /**
      * Same as {@link AudioSystem#setCurrentImeUid(int)}
      * Communicate UID of current InputMethodService to audio policy service.
      */
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 4973d45..b1d300c 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1106,6 +1106,11 @@
             return Settings.Secure.getInt(context.getContentResolver(),
                     CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
         }
+
+        public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
+            return Settings.Secure.getInt(context.getContentResolver(),
+                    CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
+        }
     }
 
     /**
@@ -1137,6 +1142,8 @@
         //  by default.
         CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
         coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
+        coexCoordinator.setFaceHapticDisabledWhenNonBypass(
+                injector.isCoexFaceNonBypassHapticsDisabled(context));
 
         try {
             injector.getActivityManagerService().registerUserSwitchObserver(
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 013c74d..6f38ed0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -54,12 +54,18 @@
     public static final int STATE_NEW = 0;
     // Framework/HAL have started this operation
     public static final int STATE_STARTED = 1;
-    // Operation is started, but requires some user action (such as finger lift & re-touch)
+    // Operation is started, but requires some user action to start (such as finger lift & re-touch)
     public static final int STATE_STARTED_PAUSED = 2;
+    // Same as above, except auth was attempted (rejected, timed out, etc).
+    public static final int STATE_STARTED_PAUSED_ATTEMPTED = 3;
     // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
-    public static final int STATE_STOPPED = 3;
+    public static final int STATE_STOPPED = 4;
 
-    @IntDef({STATE_NEW, STATE_STARTED, STATE_STARTED_PAUSED, STATE_STOPPED})
+    @IntDef({STATE_NEW,
+            STATE_STARTED,
+            STATE_STARTED_PAUSED,
+            STATE_STARTED_PAUSED_ATTEMPTED,
+            STATE_STOPPED})
     @interface State {}
 
     private final boolean mIsStrongBiometric;
@@ -76,7 +82,7 @@
 
     private long mStartTimeMs;
 
-    protected boolean mAuthAttempted;
+    private boolean mAuthAttempted;
 
     // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
     //  the state. We should think of a way to improve this in the future.
@@ -92,6 +98,12 @@
      */
     protected abstract void handleLifecycleAfterAuth(boolean authenticated);
 
+    /**
+     * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched.
+     *         etc)
+     */
+    public abstract boolean wasUserDetected();
+
     public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
             int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -174,7 +186,8 @@
                 + ", isBP: " + isBiometricPrompt()
                 + ", listener: " + listener
                 + ", requireConfirmation: " + mRequireConfirmation
-                + ", user: " + getTargetUserId());
+                + ", user: " + getTargetUserId()
+                + ", clientMonitor: " + toString());
 
         final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
         if (isCryptoOperation()) {
@@ -298,6 +311,11 @@
                 public void handleLifecycleAfterAuth() {
                     AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
                 }
+
+                @Override
+                public void sendAuthenticationCanceled() {
+                    sendCancelOnly(listener);
+                }
             });
         } else {
             // Allow system-defined limit of number of attempts before giving up
@@ -332,10 +350,30 @@
                 public void handleLifecycleAfterAuth() {
                     AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
                 }
+
+                @Override
+                public void sendAuthenticationCanceled() {
+                    sendCancelOnly(listener);
+                }
             });
         }
     }
 
+    private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) {
+        if (listener == null) {
+            Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null");
+            return;
+        }
+        try {
+            listener.onError(getSensorId(),
+                    getCookie(),
+                    BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                    0 /* vendorCode */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
     @Override
     public void onAcquired(int acquiredInfo, int vendorCode) {
         super.onAcquired(acquiredInfo, vendorCode);
@@ -349,9 +387,11 @@
     }
 
     @Override
-    public void onError(int errorCode, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) {
         super.onError(errorCode, vendorCode);
         mState = STATE_STOPPED;
+
+        CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError);
     }
 
     /**
@@ -413,4 +453,8 @@
     public boolean interruptsPrecedingClients() {
         return true;
     }
+
+    public boolean wasAuthAttempted() {
+        return mAuthAttempted;
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index b576673..25d4a38 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricConstants;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Slog;
@@ -45,6 +46,8 @@
     private static final String TAG = "BiometricCoexCoordinator";
     public static final String SETTING_ENABLE_NAME =
             "com.android.server.biometrics.sensors.CoexCoordinator.enable";
+    public static final String FACE_HAPTIC_DISABLE =
+            "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics";
     private static final boolean DEBUG = true;
 
     // Successful authentications should be used within this amount of time.
@@ -52,7 +55,7 @@
 
     /**
      * Callback interface notifying the owner of "results" from the CoexCoordinator's business
-     * logic.
+     * logic for accept and reject.
      */
     interface Callback {
         /**
@@ -71,6 +74,22 @@
          * from scheduler if auth was successful).
          */
         void handleLifecycleAfterAuth();
+
+        /**
+         * Requests the owner to notify the caller that authentication was canceled.
+         */
+        void sendAuthenticationCanceled();
+    }
+
+    /**
+     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
+     * logic for errors.
+     */
+    interface ErrorCallback {
+        /**
+         * Requests the owner to initiate a vibration for this event.
+         */
+        void sendHapticFeedback();
     }
 
     private static CoexCoordinator sInstance;
@@ -144,6 +163,10 @@
         mAdvancedLogicEnabled = enabled;
     }
 
+    public void setFaceHapticDisabledWhenNonBypass(boolean disabled) {
+        mFaceHapticDisabledWhenNonBypass = disabled;
+    }
+
     @VisibleForTesting
     void reset() {
         mClientMap.clear();
@@ -153,6 +176,7 @@
     private final Map<Integer, AuthenticationClient<?>> mClientMap;
     @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
     private boolean mAdvancedLogicEnabled;
+    private boolean mFaceHapticDisabledWhenNonBypass;
     private final Handler mHandler;
 
     private CoexCoordinator() {
@@ -191,6 +215,9 @@
         mClientMap.remove(sensorType);
     }
 
+    /**
+     * Notify the coordinator that authentication succeeded (accepted)
+     */
     public void onAuthenticationSucceeded(long currentTimeMillis,
             @NonNull AuthenticationClient<?> client,
             @NonNull Callback callback) {
@@ -225,7 +252,11 @@
                         mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
                                 currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
                     } else {
-                        callback.sendHapticFeedback();
+                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+                            Slog.w(TAG, "Skipping face success haptic");
+                        } else {
+                            callback.sendHapticFeedback();
+                        }
                         callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
                         callback.handleLifecycleAfterAuth();
                     }
@@ -257,6 +288,9 @@
         }
     }
 
+    /**
+     * Notify the coordinator that a rejection has occurred.
+     */
     public void onAuthenticationRejected(long currentTimeMillis,
             @NonNull AuthenticationClient<?> client,
             @LockoutTracker.LockoutMode int lockoutMode,
@@ -278,12 +312,23 @@
                         // BiometricScheduler do not get stuck.
                         Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
                         callback.handleLifecycleAfterAuth();
-                    } else {
-                        // UDFPS is not actively authenticating (finger not touching, already
-                        // rejected, etc).
+                    } else if (isUdfpsAuthAttempted(udfps)) {
+                        // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still
+                        // auth after pointer goes down, it means UDFPS encountered a rejection. In
+                        // this case, we need to play the final reject haptic since face auth is
+                        // also done now.
                         callback.sendHapticFeedback();
                         callback.handleLifecycleAfterAuth();
                     }
+                    else {
+                        // UDFPS auth has never been attempted.
+                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+                            Slog.w(TAG, "Skipping face reject haptic");
+                        } else {
+                            callback.sendHapticFeedback();
+                        }
+                        callback.handleLifecycleAfterAuth();
+                    }
                 } else if (isCurrentUdfps(client)) {
                     // Face should either be running, or have already finished
                     SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis);
@@ -330,11 +375,63 @@
         }
     }
 
+    /**
+     * Notify the coordinator that an error has occurred.
+     */
+    public void onAuthenticationError(@NonNull AuthenticationClient<?> client,
+            @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) {
+        // Figure out non-coex state
+        final boolean shouldUsuallyVibrate;
+        if (isCurrentFaceAuth(client)) {
+            final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected();
+            final boolean authAttempted = client.wasAuthAttempted();
+
+            switch (error) {
+                case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
+                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+                    shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard;
+                    break;
+                default:
+                    shouldUsuallyVibrate = false;
+                    break;
+            }
+        } else {
+            shouldUsuallyVibrate = false;
+        }
+
+        // Figure out coex state
+        final boolean keyguardAdvancedLogic = mAdvancedLogicEnabled && client.isKeyguard();
+        final boolean hapticSuppressedByCoex;
+
+        if (keyguardAdvancedLogic) {
+            if (isSingleAuthOnly(client)) {
+                hapticSuppressedByCoex = false;
+            } else {
+                hapticSuppressedByCoex = isCurrentFaceAuth(client)
+                        && !client.isKeyguardBypassEnabled();
+            }
+        } else {
+            hapticSuppressedByCoex = false;
+        }
+
+        // Combine and send feedback if appropriate
+        Slog.d(TAG, "shouldUsuallyVibrate: " + shouldUsuallyVibrate
+                + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex);
+        if (shouldUsuallyVibrate && !hapticSuppressedByCoex) {
+            callback.sendHapticFeedback();
+        }
+    }
+
     @Nullable
     private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
         for (SuccessfulAuth auth : mSuccessfulAuths) {
             if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
-                Slog.d(TAG, "Removing stale auth: " + auth);
+                // TODO(b/193089985): This removes the auth but does not notify the client with
+                //  an appropriate lifecycle event (such as ERROR_CANCELED), and violates the
+                //  API contract. However, this might be OK for now since the validity duration
+                //  is way longer than the time it takes to auth with fingerprint.
+                Slog.e(TAG, "Removing stale auth: " + auth);
                 mSuccessfulAuths.remove(auth);
             } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
                 mSuccessfulAuths.remove(auth);
@@ -345,9 +442,13 @@
     }
 
     private void removeAndFinishAllFaceFromQueue() {
+        // Note that these auth are all successful, but have never notified the client (e.g.
+        // keyguard). To comply with the authentication lifecycle, we must notify the client that
+        // auth is "done". The safest thing to do is to send ERROR_CANCELED.
         for (SuccessfulAuth auth : mSuccessfulAuths) {
             if (auth.mSensorType == SENSOR_TYPE_FACE) {
-                Slog.d(TAG, "Removing from queue and finishing: " + auth);
+                Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth);
+                auth.mCallback.sendAuthenticationCanceled();
                 auth.mCallback.handleLifecycleAfterAuth();
                 mSuccessfulAuths.remove(auth);
             }
@@ -374,6 +475,13 @@
         return false;
     }
 
+    private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) {
+        if (client instanceof Udfps) {
+            return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED;
+        }
+        return false;
+    }
+
     private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
         for (AuthenticationClient<?> c : mClientMap.values()) {
             if (c == client) {
@@ -400,6 +508,7 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("Enabled: ").append(mAdvancedLogicEnabled);
+        sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass);
         sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
         for (SuccessfulAuth auth : mSuccessfulAuths) {
             sb.append(", Auth: ").append(auth.toString());
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index f7fd8d0..d66a279 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -127,7 +127,8 @@
         }
     }
 
-    private boolean wasUserDetected() {
+    @Override
+    public boolean wasUserDetected() {
         // Do not provide haptic feedback if the user was not detected, and an error (usually
         // ERROR_TIMEOUT) is received.
         return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -160,7 +161,7 @@
     }
 
     @Override
-    public void onError(int error, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
         mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                 getStartTimeMs(),
                 System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -169,25 +170,8 @@
                 vendorCode,
                 getTargetUserId()));
 
-        switch (error) {
-            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
-                if (!wasUserDetected() && !isBiometricPrompt()) {
-                    // No vibration if user was not detected on keyguard
-                    break;
-                }
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
-                if (mAuthAttempted) {
-                    // Only vibrate if auth was attempted. If the user was already locked out prior
-                    // to starting authentication, do not vibrate.
-                    vibrateError();
-                }
-                break;
-            case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL:
-                BiometricNotificationUtils.showReEnrollmentNotification(getContext());
-                break;
-            default:
-                break;
+        if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
+            BiometricNotificationUtils.showReEnrollmentNotification(getContext());
         }
 
         super.onError(error, vendorCode);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index c33b957..33950af 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -115,7 +115,8 @@
         }
     }
 
-    private boolean wasUserDetected() {
+    @Override
+    public boolean wasUserDetected() {
         // Do not provide haptic feedback if the user was not detected, and an error (usually
         // ERROR_TIMEOUT) is received.
         return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -147,7 +148,7 @@
     }
 
     @Override
-    public void onError(int error, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
         mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                 getStartTimeMs(),
                 System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -156,24 +157,6 @@
                 vendorCode,
                 getTargetUserId()));
 
-        switch (error) {
-            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
-                if (!wasUserDetected() && !isBiometricPrompt()) {
-                    // No vibration if user was not detected on keyguard
-                    break;
-                }
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
-                if (mAuthAttempted) {
-                    // Only vibrate if auth was attempted. If the user was already locked out prior
-                    // to starting authentication, do not vibrate.
-                    vibrateError();
-                }
-                break;
-            default:
-                break;
-        }
-
         super.onError(error, vendorCode);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 99e6e62..37ee76a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -106,6 +106,12 @@
     }
 
     @Override
+    public boolean wasUserDetected() {
+        // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+        return false;
+    }
+
+    @Override
     public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
             boolean authenticated, ArrayList<Byte> token) {
         super.onAuthenticated(identifier, authenticated, token);
@@ -114,7 +120,7 @@
             mState = STATE_STOPPED;
             UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         } else {
-            mState = STATE_STARTED_PAUSED;
+            mState = STATE_STARTED_PAUSED_ATTEMPTED;
         }
     }
 
@@ -188,7 +194,7 @@
     public void onPointerUp() {
         try {
             mIsPointerDown = false;
-            mState = STATE_STARTED_PAUSED;
+            mState = STATE_STARTED_PAUSED_ATTEMPTED;
             mALSProbeCallback.getProbe().disable();
             getFreshDaemon().onPointerUp(0 /* pointerId */);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 7558d15..5060744 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -112,7 +112,7 @@
             resetFailedAttempts(getTargetUserId());
             UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
         } else {
-            mState = STATE_STARTED_PAUSED;
+            mState = STATE_STARTED_PAUSED_ATTEMPTED;
             final @LockoutTracker.LockoutMode int lockoutMode =
                     mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
             if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
@@ -153,6 +153,12 @@
     }
 
     @Override
+    public boolean wasUserDetected() {
+        // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+        return false;
+    }
+
+    @Override
     public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
         mLockoutFrameworkImpl.addFailedAttemptForUser(userId);
         return super.handleFailedAttempt(userId);
@@ -206,7 +212,7 @@
     @Override
     public void onPointerUp() {
         mIsPointerDown = false;
-        mState = STATE_STARTED_PAUSED;
+        mState = STATE_STARTED_PAUSED_ATTEMPTED;
         mALSProbeCallback.getProbe().disable();
         UdfpsHelper.onFingerUp(getFreshDaemon());
 
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 54a4ad4..23f0ffb 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -52,11 +52,11 @@
     public BroadcastRadioService(Context context) {
         super(context);
 
-        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService();
+        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
         mV1Modules = mHal1.loadModules();
         OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
         mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
-                max.isPresent() ? max.getAsInt() + 1 : 0);
+                max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
     }
 
     @Override
@@ -111,7 +111,7 @@
             synchronized (mLock) {
                 if (!mHal2.hasAnyModules()) {
                     Slog.i(TAG, "There are no HAL 2.x modules registered");
-                    return new AnnouncementAggregator(listener);
+                    return new AnnouncementAggregator(listener, mLock);
                 }
 
                 return mHal2.addAnnouncementListener(enabledTypes, listener);
diff --git a/services/core/java/com/android/server/broadcastradio/OWNERS b/services/core/java/com/android/server/broadcastradio/OWNERS
index ea4421e..3e360e7 100644
--- a/services/core/java/com/android/server/broadcastradio/OWNERS
+++ b/services/core/java/com/android/server/broadcastradio/OWNERS
@@ -1,2 +1,3 @@
+keunyoung@google.com
+oscarazu@google.com
 twasilczyk@google.com
-randolphs@google.com
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
index e8ac547..5da6032 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
@@ -17,16 +17,9 @@
 package com.android.server.broadcastradio.hal1;
 
 import android.annotation.NonNull;
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.radio.IRadioService;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.RadioManager;
-import android.os.ParcelableException;
-
-import com.android.server.SystemService;
 
 import java.util.List;
 import java.util.Objects;
@@ -37,7 +30,7 @@
      */
     private final long mNativeContext = nativeInit();
 
-    private final Object mLock = new Object();
+    private final Object mLock;
 
     @Override
     protected void finalize() throws Throwable {
@@ -51,6 +44,14 @@
     private native Tuner nativeOpenTuner(long nativeContext, int moduleId,
             RadioManager.BandConfig config, boolean withAudio, ITunerCallback callback);
 
+    /**
+     * Constructor. should pass
+     * {@code com.android.server.broadcastradio.BroadcastRadioService#mLock} for lock.
+     */
+    public BroadcastRadioService(@NonNull Object lock) {
+        mLock = lock;
+    }
+
     public @NonNull List<RadioManager.ModuleProperties> loadModules() {
         synchronized (mLock) {
             return Objects.requireNonNull(nativeLoadModules(mNativeContext));
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
index 5307697..42e296f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
@@ -35,7 +35,7 @@
 public class AnnouncementAggregator extends ICloseHandle.Stub {
     private static final String TAG = "BcRadio2Srv.AnnAggr";
 
-    private final Object mLock = new Object();
+    private final Object mLock;
     @NonNull private final IAnnouncementListener mListener;
     private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient();
 
@@ -45,8 +45,9 @@
     @GuardedBy("mLock")
     private boolean mIsClosed = false;
 
-    public AnnouncementAggregator(@NonNull IAnnouncementListener listener) {
+    public AnnouncementAggregator(@NonNull IAnnouncementListener listener, @NonNull Object lock) {
         mListener = Objects.requireNonNull(listener);
+        mLock = Objects.requireNonNull(lock);
         try {
             listener.asBinder().linkToDeath(mDeathRecipient, 0);
         } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 5e79c59..5c07f76 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -42,7 +42,7 @@
 public class BroadcastRadioService {
     private static final String TAG = "BcRadio2Srv";
 
-    private final Object mLock = new Object();
+    private final Object mLock;
 
     @GuardedBy("mLock")
     private int mNextModuleId = 0;
@@ -68,7 +68,7 @@
                     moduleId = mNextModuleId;
                 }
 
-                RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName);
+                RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName, mLock);
                 if (module == null) {
                     return;
                 }
@@ -116,8 +116,9 @@
         }
     };
 
-    public BroadcastRadioService(int nextModuleId) {
+    public BroadcastRadioService(int nextModuleId, Object lock) {
         mNextModuleId = nextModuleId;
+        mLock = lock;
         try {
             IServiceManager manager = IServiceManager.getService();
             if (manager == null) {
@@ -174,7 +175,7 @@
 
     public ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
             @NonNull IAnnouncementListener listener) {
-        AnnouncementAggregator aggregator = new AnnouncementAggregator(listener);
+        AnnouncementAggregator aggregator = new AnnouncementAggregator(listener, mLock);
         boolean anySupported = false;
         synchronized (mLock) {
             for (RadioModule module : mModules.values()) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index b7e188c..ef7f4c9 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -58,7 +58,7 @@
     @NonNull private final IBroadcastRadio mService;
     @NonNull public final RadioManager.ModuleProperties mProperties;
 
-    private final Object mLock = new Object();
+    private final Object mLock;
     @NonNull private final Handler mHandler;
 
     @GuardedBy("mLock")
@@ -132,13 +132,15 @@
 
     @VisibleForTesting
     RadioModule(@NonNull IBroadcastRadio service,
-            @NonNull RadioManager.ModuleProperties properties) {
+            @NonNull RadioManager.ModuleProperties properties, @NonNull Object lock) {
         mProperties = Objects.requireNonNull(properties);
         mService = Objects.requireNonNull(service);
+        mLock = Objects.requireNonNull(lock);
         mHandler = new Handler(Looper.getMainLooper());
     }
 
-    public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
+    public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName,
+            Object lock) {
         try {
             IBroadcastRadio service = IBroadcastRadio.getService(fqName);
             if (service == null) return null;
@@ -156,7 +158,7 @@
             RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
                     service.getProperties(), amfmConfig.value, dabConfig.value);
 
-            return new RadioModule(service, prop);
+            return new RadioModule(service, prop, lock);
         } catch (RemoteException ex) {
             Slog.e(TAG, "failed to load module " + fqName, ex);
             return null;
@@ -178,7 +180,8 @@
                 });
                 mHalTunerSession = Objects.requireNonNull(hwSession.value);
             }
-            TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb);
+            TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb,
+                    mLock);
             mAidlTunerSessions.add(tunerSession);
 
             // Propagate state to new client. Note: These callbacks are invoked while holding mLock
@@ -377,7 +380,7 @@
             }
         };
 
-        synchronized (mService) {
+        synchronized (mLock) {
             mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
                 halResult.value = result;
                 hwCloseHandle.value = closeHnd;
@@ -401,7 +404,7 @@
         if (id == 0) throw new IllegalArgumentException("Image ID is missing");
 
         byte[] rawImage;
-        synchronized (mService) {
+        synchronized (mLock) {
             List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
             rawImage = new byte[rawList.size()];
             for (int i = 0; i < rawList.size(); i++) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 7ab3bdd..200af2f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -40,7 +40,7 @@
     private static final String TAG = "BcRadio2Srv.session";
     private static final String kAudioDeviceName = "Radio tuner source";
 
-    private final Object mLock = new Object();
+    private final Object mLock;
 
     private final RadioModule mModule;
     private final ITunerSession mHwSession;
@@ -53,10 +53,12 @@
     private RadioManager.BandConfig mDummyConfig = null;
 
     TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
-            @NonNull android.hardware.radio.ITunerCallback callback) {
+            @NonNull android.hardware.radio.ITunerCallback callback,
+            @NonNull Object lock) {
         mModule = Objects.requireNonNull(module);
         mHwSession = Objects.requireNonNull(hwSession);
         mCallback = Objects.requireNonNull(callback);
+        mLock = Objects.requireNonNull(lock);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index ed7d185..6610e8c 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -20,9 +20,14 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.compat.CompatChanges;
 import android.app.TaskStackListener;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.Overridable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -49,6 +54,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.stats.camera.nano.CameraProtos.CameraStreamProto;
 import android.util.ArrayMap;
@@ -97,6 +103,95 @@
 
     public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
 
+    /**
+     * When enabled this change id forces the packages it is applied to override the default
+     * camera rotate & crop behavior. The default behavior along with all possible override
+     * combinations is discussed in the table below.
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    @TestApi
+    public static final long OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS = 189229956L; // buganizer id
+
+    /**
+     * When enabled this change id forces the packages it is applied to ignore the current value of
+     * 'android:resizeableActivity' as well as target SDK equal to or below M and consider the
+     * activity as non-resizeable. In this case, the value of camera rotate & crop will only depend
+     * on potential mismatches between the orientation of the camera and the fixed orientation of
+     * the activity. You can check the table below for further details on the possible override
+     * combinations.
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    @TestApi
+    public static final long OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK = 191513214L; // buganizer id
+
+    /**
+     * This change id forces the packages it is applied to override the default camera rotate & crop
+     * behavior. Enabling it will set the crop & rotate parameter to
+     * {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_90} and disabling it
+     * will reset the parameter to
+     * {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_NONE} as long as camera
+     * clients include {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_AUTO}
+     * in their capture requests.
+     *
+     * This treatment only takes effect if OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS is also enabled.
+     * The table below includes further information about the possible override combinations.
+     */
+    @ChangeId
+    @Overridable
+    @Disabled
+    @TestApi
+    public static final long OVERRIDE_CAMERA_ROTATE_AND_CROP = 190069291L; //buganizer id
+
+    /**
+     * Possible override combinations
+     *
+     *            |OVERRIDE     |          |OVERRIDE_
+     *            |CAMERA_      |OVERRIDE  |CAMERA_
+     *            |ROTATE_      |CAMERA_   |RESIZEABLE_
+     *            |AND_CROP_    |ROTATE_   |AND_SDK_
+     *            |DEFAULTS     |AND_CROP  |CHECK
+     * ______________________________________________
+     * Default    |             |          |
+     * Behavior   | D           |D         |D
+     * ______________________________________________
+     * Ignore     |             |          |
+     * SDK&Resize | D           |D         |E
+     * ______________________________________________
+     * Default    |             |          |
+     * Behavior   | D           |E         |D
+     * ______________________________________________
+     * Ignore     |             |          |
+     * SDK&Resize | D           |E         |E
+     * ______________________________________________
+     * Rotate&Crop|             |          |
+     * disabled   | E           |D         |D
+     * ______________________________________________
+     * Rotate&Crop|             |          |
+     * disabled   | E           |D         |E
+     * ______________________________________________
+     * Rotate&Crop|             |          |
+     * enabled    | E           |E         |D
+     * ______________________________________________
+     * Rotate&Crop|             |          |
+     * enabled    | E           |E         |E
+     * ______________________________________________
+     * Where:
+     * E -> Override enabled
+     * D -> Override disabled
+     * Default behavior ->  Rotate&crop will be enabled only in cases
+     *                      where the fixed app orientation mismatches
+     *                      with the orientation of the camera.
+     *                      Additionally the app must either target M (or below)
+     *                      or is declared as non-resizeable.
+     * Ignore SDK&Resize -> Rotate&crop will be enabled only in cases
+     *                      where the fixed app orientation mismatches
+     *                      with the orientation of the camera.
+     */
+
     // Flags arguments to NFC adapter to enable/disable NFC
     public static final int DISABLE_POLLING_FLAGS = 0x1000;
     public static final int ENABLE_POLLING_FLAGS = 0x0000;
@@ -257,6 +352,7 @@
         private boolean isFixedOrientationLandscape;
         private boolean isFixedOrientationPortrait;
         private int displayId;
+        private int userId;
     }
 
     private final class TaskStateHandler extends TaskStackListener {
@@ -273,6 +369,7 @@
                 info.frontTaskId = taskInfo.taskId;
                 info.isResizeable = taskInfo.isResizeable;
                 info.displayId = taskInfo.displayId;
+                info.userId = taskInfo.userId;
                 info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape(
                         taskInfo.topActivityInfo.screenOrientation);
                 info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait(
@@ -303,7 +400,7 @@
             Log.e(TAG, "Top task with package name: " + packageName + " not found!");
             return null;
         }
-    };
+    }
 
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -345,7 +442,8 @@
          * Gets whether crop-rotate-scale is needed.
          */
         private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName,
-                @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) {
+                @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing,
+                boolean ignoreResizableAndSdkCheck) {
             if (taskInfo == null) {
                 return false;
             }
@@ -357,9 +455,11 @@
                 return false;
             }
 
-            // Only enable the crop-rotate-scale workaround if the app targets M or below and is not
+            // In case the activity behavior is not explicitly overridden, enable the
+            // crop-rotate-scale workaround if the app targets M (or below) or is not
             // resizeable.
-            if (!isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
+            if (!ignoreResizableAndSdkCheck && !isMOrBelow(ctx, packageName) &&
+                    taskInfo.isResizeable) {
                 Slog.v(TAG,
                         "The activity is N or above and claims to support resizeable-activity. "
                                 + "Crop-rotate-scale is disabled.");
@@ -367,22 +467,32 @@
             }
 
             DisplayManager displayManager = ctx.getSystemService(DisplayManager.class);
-            Display display = displayManager.getDisplay(taskInfo.displayId);
-            int rotation = display.getRotation();
             int rotationDegree = 0;
-            switch (rotation) {
-                case Surface.ROTATION_0:
-                    rotationDegree = 0;
-                    break;
-                case Surface.ROTATION_90:
-                    rotationDegree = 90;
-                    break;
-                case Surface.ROTATION_180:
-                    rotationDegree = 180;
-                    break;
-                case Surface.ROTATION_270:
-                    rotationDegree = 270;
-                    break;
+            if (displayManager != null) {
+                Display display = displayManager.getDisplay(taskInfo.displayId);
+                if (display == null) {
+                    Slog.e(TAG, "Invalid display id: " + taskInfo.displayId);
+                    return false;
+                }
+
+                int rotation = display.getRotation();
+                switch (rotation) {
+                    case Surface.ROTATION_0:
+                        rotationDegree = 0;
+                        break;
+                    case Surface.ROTATION_90:
+                        rotationDegree = 90;
+                        break;
+                    case Surface.ROTATION_180:
+                        rotationDegree = 180;
+                        break;
+                    case Surface.ROTATION_270:
+                        rotationDegree = 270;
+                        break;
+                }
+            } else {
+                Slog.e(TAG, "Failed to query display manager!");
+                return false;
             }
 
             // Here we only need to know whether the camera is landscape or portrait. Therefore we
@@ -414,9 +524,28 @@
             //  regions in capture requests/results to account for thea physical rotation. The
             //  former is somewhat tricky as it assumes that camera clients always check for the
             //  current value by retrieving the camera characteristics from the camera device.
-            return getNeedCropRotateScale(mContext, packageName,
-                    mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation,
-                    lensFacing);
+            TaskInfo taskInfo = mTaskStackListener.getFrontTaskInfo(packageName);
+            if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
+                        OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS, packageName,
+                        UserHandle.getUserHandleForUid(taskInfo.userId)))) {
+                if (CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_ROTATE_AND_CROP, packageName,
+                        UserHandle.getUserHandleForUid(taskInfo.userId))) {
+                    Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP enabled!");
+                    return true;
+                } else {
+                    Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP disabled!");
+                    return false;
+                }
+            }
+            boolean ignoreResizableAndSdkCheck = false;
+            if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
+                    OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK, packageName,
+                    UserHandle.getUserHandleForUid(taskInfo.userId)))) {
+                Slog.v(TAG, "OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK enabled!");
+                ignoreResizableAndSdkCheck = true;
+            }
+            return getNeedCropRotateScale(mContext, packageName, taskInfo, sensorOrientation,
+                    lensFacing, ignoreResizableAndSdkCheck);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 56b68b7..eed68f8 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -27,7 +27,9 @@
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * ShellCommands for {@link DeviceStateManagerService}.
@@ -56,14 +58,18 @@
         switch (cmd) {
             case "state":
                 return runState(pw);
+            case "print-state":
+                return runPrintState(pw);
             case "print-states":
                 return runPrintStates(pw);
+            case "print-states-simple":
+                return runPrintStatesSimple(pw);
             default:
                 return handleDefaultCommands(cmd);
         }
     }
 
-    private void printState(PrintWriter pw) {
+    private void printAllStates(PrintWriter pw) {
         Optional<DeviceState> committedState = mService.getCommittedState();
         Optional<DeviceState> baseState = mService.getBaseState();
         Optional<DeviceState> overrideState = mService.getOverrideState();
@@ -79,7 +85,8 @@
     private int runState(PrintWriter pw) {
         final String nextArg = getNextArg();
         if (nextArg == null) {
-            printState(pw);
+            printAllStates(pw);
+            return 0;
         }
 
         final Context context = mService.getContext();
@@ -123,6 +130,16 @@
         return 0;
     }
 
+    private int runPrintState(PrintWriter pw) {
+        Optional<DeviceState> deviceState = mService.getCommittedState();
+        if (deviceState.isPresent()) {
+            pw.println(deviceState.get().getIdentifier());
+            return 0;
+        }
+        getErrPrintWriter().println("Error: device state not available.");
+        return 1;
+    }
+
     private int runPrintStates(PrintWriter pw) {
         DeviceState[] states = mService.getSupportedStates();
         pw.print("Supported states: [\n");
@@ -133,6 +150,14 @@
         return 0;
     }
 
+    private int runPrintStatesSimple(PrintWriter pw) {
+        pw.print(Arrays.stream(mService.getSupportedStates())
+                .map(DeviceState::getIdentifier)
+                .map(Object::toString)
+                .collect(Collectors.joining(",")));
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -141,8 +166,12 @@
         pw.println("    Print this help text.");
         pw.println("  state [reset|OVERRIDE_DEVICE_STATE]");
         pw.println("    Return or override device state.");
+        pw.println("  print-state");
+        pw.println("    Return the current device state.");
         pw.println("  print-states");
         pw.println("    Return list of currently supported device states.");
+        pw.println("  print-states-simple");
+        pw.println("    Return the currently supported device states in comma separated format.");
     }
 
     private static String toString(@NonNull Optional<DeviceState> state) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9f806af..806bcc2 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,7 +16,9 @@
 
 package com.android.server.display;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
@@ -105,6 +107,34 @@
     }
 
     /**
+     * Returns the window token of the level of the WindowManager hierarchy to mirror, or null
+     * if layer mirroring by SurfaceFlinger should not be performed.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    @Nullable
+    public IBinder getWindowTokenClientToMirrorLocked() {
+        return null;
+    }
+
+    /**
+     * Updates the window token of the level of the level of the WindowManager hierarchy to mirror.
+     * If windowToken is null, then no layer mirroring by SurfaceFlinger to should be performed.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+    }
+
+    /**
+     * Returns the default size of the surface associated with the display, or null if the surface
+     * is not provided for layer mirroring by SurfaceFlinger.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    @Nullable
+    public Point getDisplaySurfaceDefaultSize() {
+        return null;
+    }
+
+    /**
      * Gets the name of the display device.
      *
      * @return The display device name.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7d06d6e..1adcf40 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -63,8 +63,6 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
-import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
-import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
 import android.hardware.display.DisplayViewport;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -636,6 +634,9 @@
         synchronized (mSyncRoot) {
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
             if (display != null) {
+                // Do not let constrain be overwritten by override from WindowManager.
+                info.shouldConstrainMetricsForLauncher =
+                        display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher;
                 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
                     handleLogicalDisplayChangedLocked(display);
                     scheduleTraversalLocked(false);
@@ -1723,6 +1724,21 @@
         }
     }
 
+    void setShouldConstrainMetricsForLauncher(boolean constrain) {
+        // Apply constrain for every display.
+        synchronized (mSyncRoot) {
+            int[] displayIds = mLogicalDisplayMapper.getDisplayIdsLocked(Process.myUid());
+            for (int i : displayIds) {
+                final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(i);
+                if (display == null) {
+                    return;
+                }
+                display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher = constrain;
+                setDisplayInfoOverrideFromWindowManagerInternal(i, display.getDisplayInfoLocked());
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mViewports.clear();
     }
@@ -1749,10 +1765,13 @@
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
 
+        // Mirror the part of WM hierarchy that corresponds to the provided window token.
+        IBinder windowTokenClientToMirror = device.getWindowTokenClientToMirrorLocked();
+
         // Find the logical display that the display device is showing.
         // Certain displays only ever show their own content.
         LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
-        if (!ownContent) {
+        if (!ownContent && windowTokenClientToMirror == null) {
             if (display != null && !display.hasContentLocked()) {
                 // If the display does not have any content of its own, then
                 // automatically mirror the requested logical display contents if possible.
@@ -3285,6 +3304,9 @@
 
             synchronized (mSyncRoot) {
                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+                if (display == null) {
+                    return null;
+                }
                 final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
                 if (device == null) {
                     return null;
@@ -3311,6 +3333,40 @@
             }
             return config.getRefreshRateLimitations();
         }
+
+        @Override
+        public IBinder getWindowTokenClientToMirror(int displayId) {
+            final DisplayDevice device;
+            synchronized (mSyncRoot) {
+                device = getDeviceForDisplayLocked(displayId);
+                if (device == null) {
+                    return null;
+                }
+            }
+            return device.getWindowTokenClientToMirrorLocked();
+        }
+
+        @Override
+        public void setWindowTokenClientToMirror(int displayId, IBinder windowToken) {
+            synchronized (mSyncRoot) {
+                final DisplayDevice device = getDeviceForDisplayLocked(displayId);
+                if (device != null) {
+                    device.setWindowTokenClientToMirrorLocked(windowToken);
+                }
+            }
+        }
+
+        @Override
+        public Point getDisplaySurfaceDefaultSize(int displayId) {
+            final DisplayDevice device;
+            synchronized (mSyncRoot) {
+                device = getDeviceForDisplayLocked(displayId);
+                if (device == null) {
+                    return null;
+                }
+            }
+            return device.getDisplaySurfaceDefaultSize();
+        }
     }
 
     class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 48edb73..94e64f0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -58,6 +58,8 @@
                 return setDisplayModeDirectorLoggingEnabled(false);
             case "dwb-set-cct":
                 return setAmbientColorTemperatureOverride();
+            case "constrain-launcher-metrics":
+                return setConstrainLauncherMetrics();
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -88,6 +90,9 @@
         pw.println("    Disable display mode director logging.");
         pw.println("  dwb-set-cct CCT");
         pw.println("    Sets the ambient color temperature override to CCT (use -1 to disable).");
+        pw.println("  constrain-launcher-metrics [true|false]");
+        pw.println("    Sets if Display#getRealSize and getRealMetrics should be constrained for ");
+        pw.println("    Launcher.");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
@@ -150,4 +155,15 @@
         mService.setAmbientColorTemperatureOverride(cct);
         return 0;
     }
+
+    private int setConstrainLauncherMetrics() {
+        String constrainText = getNextArg();
+        if (constrainText == null) {
+            getErrPrintWriter().println("Error: no value specified");
+            return 1;
+        }
+        boolean constrain = Boolean.parseBoolean(constrainText);
+        mService.setShouldConstrainMetricsForLauncher(constrain);
+        return 0;
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index b0ad118..a25cfd8 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -52,6 +52,7 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
@@ -153,7 +154,7 @@
                 updateVoteLocked(displayId, priority, vote);
             }
         };
-        mSensorObserver = new SensorObserver(context, ballotBox);
+        mSensorObserver = new SensorObserver(context, ballotBox, injector);
         mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
         mDeviceConfig = injector.getDeviceConfig();
@@ -2129,27 +2130,36 @@
         }
     }
 
-    private static class SensorObserver implements ProximityActiveListener {
-        private static final String PROXIMITY_SENSOR_NAME = null;
-        private static final String PROXIMITY_SENSOR_TYPE = Sensor.STRING_TYPE_PROXIMITY;
+    private static final class SensorObserver implements ProximityActiveListener,
+            DisplayManager.DisplayListener {
+        private final String mProximitySensorName = null;
+        private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
 
         private final BallotBox mBallotBox;
         private final Context mContext;
+        private final Injector mInjector;
+        @GuardedBy("mSensorObserverLock")
+        private final SparseBooleanArray mDozeStateByDisplay = new SparseBooleanArray();
+        private final Object mSensorObserverLock = new Object();
 
         private DisplayManager mDisplayManager;
         private DisplayManagerInternal mDisplayManagerInternal;
+        @GuardedBy("mSensorObserverLock")
         private boolean mIsProxActive = false;
 
-        SensorObserver(Context context, BallotBox ballotBox) {
+        SensorObserver(Context context, BallotBox ballotBox, Injector injector) {
             mContext = context;
             mBallotBox = ballotBox;
+            mInjector = injector;
         }
 
         @Override
         public void onProximityActive(boolean isActive) {
-            if (mIsProxActive != isActive) {
-                mIsProxActive = isActive;
-                recalculateVotes();
+            synchronized (mSensorObserverLock) {
+                if (mIsProxActive != isActive) {
+                    mIsProxActive = isActive;
+                    recalculateVotesLocked();
+                }
             }
         }
 
@@ -2160,17 +2170,27 @@
             final SensorManagerInternal sensorManager =
                     LocalServices.getService(SensorManagerInternal.class);
             sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
+
+            synchronized (mSensorObserverLock) {
+                for (Display d : mDisplayManager.getDisplays()) {
+                    mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
+                }
+            }
+            mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
+                    DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                            | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                            | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
         }
 
-        private void recalculateVotes() {
+        private void recalculateVotesLocked() {
             final Display[] displays = mDisplayManager.getDisplays();
             for (Display d : displays) {
                 int displayId = d.getDisplayId();
                 Vote vote = null;
-                if (mIsProxActive) {
+                if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) {
                     final RefreshRateRange rate =
                             mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
-                                    displayId, PROXIMITY_SENSOR_NAME, PROXIMITY_SENSOR_TYPE);
+                                    displayId, mProximitySensorName, mProximitySensorType);
                     if (rate != null) {
                         vote = Vote.forRefreshRates(rate.min, rate.max);
                     }
@@ -2181,7 +2201,44 @@
 
         void dumpLocked(PrintWriter pw) {
             pw.println("  SensorObserver");
-            pw.println("    mIsProxActive=" + mIsProxActive);
+            synchronized (mSensorObserverLock) {
+                pw.println("    mIsProxActive=" + mIsProxActive);
+                pw.println("    mDozeStateByDisplay:");
+                for (int i = 0; i < mDozeStateByDisplay.size(); i++) {
+                    final int id = mDozeStateByDisplay.keyAt(i);
+                    final boolean dozed = mDozeStateByDisplay.valueAt(i);
+                    pw.println("      " + id + " -> " + dozed);
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            boolean isDozeState = mInjector.isDozeState(mDisplayManager.getDisplay(displayId));
+            synchronized (mSensorObserverLock) {
+                mDozeStateByDisplay.put(displayId, isDozeState);
+                recalculateVotesLocked();
+            }
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            boolean wasDozeState = mDozeStateByDisplay.get(displayId);
+            synchronized (mSensorObserverLock) {
+                mDozeStateByDisplay.put(displayId,
+                        mInjector.isDozeState(mDisplayManager.getDisplay(displayId)));
+                if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
+                    recalculateVotesLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            synchronized (mSensorObserverLock) {
+                mDozeStateByDisplay.delete(displayId);
+                recalculateVotesLocked();
+            }
         }
     }
 
@@ -2413,6 +2470,8 @@
                 Handler handler, long flags);
 
         BrightnessInfo getBrightnessInfo(int displayId);
+
+        boolean isDozeState(Display d);
     }
 
     @VisibleForTesting
@@ -2465,6 +2524,14 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            if (d == null) {
+                return false;
+            }
+            return Display.isDozeState(d.getState());
+        }
+
         private DisplayManager getDisplayManager() {
             if (mDisplayManager == null) {
                 mDisplayManager = mContext.getSystemService(DisplayManager.class);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 59f536c..1108937 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2342,7 +2342,7 @@
             try {
                 // TODO(brightnessfloat): change BatteryStats to use float
                 mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt(
-                        brightness, null));
+                        brightness));
             } catch (RemoteException e) {
                 // same process
             }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 24d29d3..1769712 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -601,12 +601,6 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
-                    if (res.getBoolean(
-                            com.android.internal.R.bool.config_maskMainBuiltInDisplayCutout)) {
-                        mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
-                    }
-                    mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
-                            mInfo.width, mInfo.height);
                     mInfo.roundedCorners = RoundedCorners.fromResources(
                             res, mInfo.width, mInfo.height);
                 } else {
@@ -620,6 +614,12 @@
                     }
                 }
 
+                if (DisplayCutout.getMaskBuiltInDisplayCutout(res, mInfo.uniqueId)) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
+                }
+                mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
+                        mInfo.uniqueId, mInfo.width, mInfo.height);
+
                 if (mStaticDisplayInfo.isInternal) {
                     mInfo.type = Display.TYPE_INTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
@@ -795,12 +795,11 @@
                             mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
                                     "ScreenBrightness",
-                                    BrightnessSynchronizer.brightnessFloatToInt(
-                                            brightnessState, null));
+                                    BrightnessSynchronizer.brightnessFloatToInt(brightnessState));
                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
                                     "SdrScreenBrightness",
                                     BrightnessSynchronizer.brightnessFloatToInt(
-                                            sdrBrightnessState, null));
+                                            sdrBrightnessState));
                         } finally {
                             Trace.traceEnd(Trace.TRACE_TAG_POWER);
                         }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 5186744..86c9ca9 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -233,6 +233,8 @@
                 info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
                 info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
                 info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
+                info.shouldConstrainMetricsForLauncher =
+                        mOverrideDisplayInfo.shouldConstrainMetricsForLauncher;
             }
             mInfo.set(info);
         }
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index b7931c8..34d2b01 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -31,7 +31,9 @@
 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Point;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
 import android.media.projection.IMediaProjection;
@@ -231,6 +233,7 @@
         private Display.Mode mMode;
         private boolean mIsDisplayOn;
         private int mDisplayIdToMirror;
+        private IBinder mWindowTokenClientToMirror;
 
         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                 int ownerUid, String ownerPackageName, Surface surface, int flags,
@@ -253,6 +256,7 @@
             mUniqueIndex = uniqueIndex;
             mIsDisplayOn = surface != null;
             mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
+            mWindowTokenClientToMirror = virtualDisplayConfig.getWindowTokenClientToMirror();
         }
 
         @Override
@@ -282,6 +286,26 @@
             return mDisplayIdToMirror;
         }
 
+        @Override
+        @Nullable
+        public IBinder getWindowTokenClientToMirrorLocked() {
+            return mWindowTokenClientToMirror;
+        }
+
+        @Override
+        public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+            if (mWindowTokenClientToMirror != windowToken) {
+                mWindowTokenClientToMirror = windowToken;
+                sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+                sendTraversalRequestLocked();
+            }
+        }
+
+        @Override
+        public Point getDisplaySurfaceDefaultSize() {
+            return mSurface.getDefaultSize();
+        }
+
         @VisibleForTesting
         Surface getSurfaceLocked() {
             return mSurface;
@@ -362,6 +386,7 @@
             pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
             pw.println("mStopped=" + mStopped);
             pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
+            pw.println("mWindowTokenClientToMirror=" + mWindowTokenClientToMirror);
         }
 
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index ad2ef2a..05e764b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -94,6 +94,21 @@
 
     private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
 
+    /*
+     * The three flags below determine the action when a message is received. If CEC_DISABLED_IGNORE
+     * bit is set in ACTION_ON_RECEIVE_MSG, then the message is forwarded irrespective of whether
+     * CEC is enabled or disabled. The other flags/bits are also ignored.
+     */
+    private static final int CEC_DISABLED_IGNORE = 1 << 0;
+
+    /* If CEC_DISABLED_LOG_WARNING bit is set, a warning message is printed if CEC is disabled. */
+    private static final int CEC_DISABLED_LOG_WARNING = 1 << 1;
+
+    /* If CEC_DISABLED_DROP_MSG bit is set, the message is dropped if CEC is disabled. */
+    private static final int CEC_DISABLED_DROP_MSG = 1 << 2;
+
+    private static final int ACTION_ON_RECEIVE_MSG = CEC_DISABLED_LOG_WARNING;
+
     /** Cookie for matching the right end point. */
     protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353;
 
@@ -568,6 +583,16 @@
     @VisibleForTesting
     void onReceiveCommand(HdmiCecMessage message) {
         assertRunOnServiceThread();
+        if (((ACTION_ON_RECEIVE_MSG & CEC_DISABLED_IGNORE) == 0)
+                && !mService.isControlEnabled()
+                && !HdmiCecMessage.isCecTransportMessage(message.getOpcode())) {
+            if ((ACTION_ON_RECEIVE_MSG & CEC_DISABLED_LOG_WARNING) != 0) {
+                HdmiLogger.warning("Message " + message + " received when cec disabled");
+            }
+            if ((ACTION_ON_RECEIVE_MSG & CEC_DISABLED_DROP_MSG) != 0) {
+                return;
+            }
+        }
         if (mService.isAddressAllocated() && !isAcceptableAddress(message.getDestination())) {
             return;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index 15a3167..e3292a3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -307,5 +307,16 @@
     private static boolean isUserControlPressedMessage(int opcode) {
         return Constants.MESSAGE_USER_CONTROL_PRESSED == opcode;
     }
+
+    static boolean isCecTransportMessage(int opcode) {
+        switch (opcode) {
+            case Constants.MESSAGE_REQUEST_CURRENT_LATENCY:
+            case Constants.MESSAGE_REPORT_CURRENT_LATENCY:
+            case Constants.MESSAGE_CDC_MESSAGE:
+                return true;
+            default:
+                return false;
+        }
+    }
 }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d3aa3fa..0c55138 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -681,6 +681,12 @@
         // on boot, if device is interactive, set HDMI CEC state as powered on as well
         if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
             mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
+            // Start all actions that were queued because the device was in standby
+            if (mAddressAllocated) {
+                for (HdmiCecLocalDevice localDevice : getAllLocalDevices()) {
+                    localDevice.startQueuedActions();
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/RequestSadAction.java b/services/core/java/com/android/server/hdmi/RequestSadAction.java
new file mode 100644
index 0000000..4d36078
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/RequestSadAction.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Feature action that queries the Short Audio Descriptor (SAD) of another device. This action is
+ * initiated from the Android system working as TV device to get the SAD of the connected audio
+ * system device.
+ * <p>
+ * Package-private
+ */
+final class RequestSadAction extends HdmiCecFeatureAction {
+    private static final String TAG = "RequestSadAction";
+
+    // State in which the action is waiting for <Report Short Audio Descriptor>.
+    private static final int STATE_WAITING_FOR_REPORT_SAD = 1;
+
+    private static final List<Integer> ALL_CEC_CODECS = new ArrayList<Integer>(Arrays.asList(
+            Constants.AUDIO_CODEC_LPCM,
+            Constants.AUDIO_CODEC_DD,
+            Constants.AUDIO_CODEC_MPEG1,
+            Constants.AUDIO_CODEC_MP3,
+            Constants.AUDIO_CODEC_MPEG2,
+            Constants.AUDIO_CODEC_AAC,
+            Constants.AUDIO_CODEC_DTS,
+            Constants.AUDIO_CODEC_ATRAC,
+            Constants.AUDIO_CODEC_ONEBITAUDIO,
+            Constants.AUDIO_CODEC_DDP,
+            Constants.AUDIO_CODEC_DTSHD,
+            Constants.AUDIO_CODEC_TRUEHD,
+            Constants.AUDIO_CODEC_DST,
+            Constants.AUDIO_CODEC_WMAPRO,
+            Constants.AUDIO_CODEC_MAX));
+    private static final int MAX_SAD_PER_REQUEST = 4;
+    private static final int RETRY_COUNTER_MAX = 1;
+    private final int mTargetAddress;
+    private final RequestSadCallback mCallback;
+    // List of all valid SADs reported by the target device. Not parsed nor deduplicated.
+    private final List<byte[]> mSupportedSads = new ArrayList<>();
+    private int mQueriedSadCount = 0; // Number of SADs queries that has already been completed
+    private int mTimeoutRetry = 0; // Number of times we have already retried on time-out
+
+    /**
+     * Constructor.
+     *
+     * @param source        an instance of {@link HdmiCecLocalDevice}.
+     * @param targetAddress the logical address the SAD is directed at.
+     */
+    RequestSadAction(HdmiCecLocalDevice source, int targetAddress, RequestSadCallback callback) {
+        super(source);
+        mTargetAddress = targetAddress;
+        mCallback = Objects.requireNonNull(callback);
+    }
+
+
+    @Override
+    boolean start() {
+        querySad();
+        return true;
+    }
+
+    private void querySad() {
+        if (mQueriedSadCount >= ALL_CEC_CODECS.size()) {
+            wrapUpAndFinish();
+            return;
+        }
+        int[] codecsToQuery = ALL_CEC_CODECS.subList(mQueriedSadCount,
+                Math.min(ALL_CEC_CODECS.size(), mQueriedSadCount + MAX_SAD_PER_REQUEST))
+                    .stream().mapToInt(i -> i).toArray();
+        sendCommand(HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(getSourceAddress(),
+                mTargetAddress, codecsToQuery));
+        mState = STATE_WAITING_FOR_REPORT_SAD;
+        addTimer(mState, HdmiConfig.TIMEOUT_MS);
+    }
+
+    @Override
+    boolean processCommand(HdmiCecMessage cmd) {
+        if (mState != STATE_WAITING_FOR_REPORT_SAD
+                || mTargetAddress != cmd.getSource()) {
+            return false;
+        }
+        if (cmd.getOpcode() == Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR) {
+            if (cmd.getParams() == null || cmd.getParams().length == 0
+                    || cmd.getParams().length % 3 != 0) {
+                // Invalid message. Wait for time-out and query again.
+                return true;
+            }
+            for (int i = 0; i < cmd.getParams().length - 2; i += 3) {
+                if (isValidCodec(cmd.getParams()[i])) {
+                    byte[] sad = new byte[]{cmd.getParams()[i], cmd.getParams()[i + 1],
+                            cmd.getParams()[i + 2]};
+                    updateResult(sad);
+                }
+                // Don't include invalid codecs in the result. Don't query again.
+                Slog.w(TAG, "Received invalid codec " + cmd.getParams()[i] + ".");
+            }
+            mQueriedSadCount += MAX_SAD_PER_REQUEST;
+            mTimeoutRetry = 0;
+            querySad();
+            return true;
+        }
+        if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
+                && (cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR
+                && (cmd.getParams()[1] & 0xFF) == Constants.ABORT_INVALID_OPERAND) {
+            // Queried SADs are not supported
+            mQueriedSadCount += MAX_SAD_PER_REQUEST;
+            mTimeoutRetry = 0;
+            querySad();
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isValidCodec(byte codec) {
+        return Constants.AUDIO_CODEC_NONE < (codec & 0xFF)
+                && (codec & 0xFF) <= Constants.AUDIO_CODEC_MAX;
+    }
+
+    private void updateResult(byte[] sad) {
+        mSupportedSads.add(sad);
+    }
+
+    @Override
+    void handleTimerEvent(int state) {
+        if (mState != state) {
+            return;
+        }
+        if (state == STATE_WAITING_FOR_REPORT_SAD) {
+            if (++mTimeoutRetry <= RETRY_COUNTER_MAX) {
+                querySad();
+                return;
+            }
+            mQueriedSadCount += MAX_SAD_PER_REQUEST;
+            mTimeoutRetry = 0;
+            querySad();
+        }
+    }
+
+    private void wrapUpAndFinish() {
+        mCallback.onRequestSadDone(mSupportedSads);
+        finish();
+    }
+
+    /**
+     * Interface used to report result of SAD request.
+     */
+    interface RequestSadCallback {
+        /**
+         * Called when SAD request is done.
+         *
+         * @param sads a list of all supported SADs. It can be an empty list.
+         */
+        void onRequestSadDone(List<byte[]> supportedSads);
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index d3083ca..c905fe0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -189,7 +189,7 @@
     private final InputManagerHandler mHandler;
 
     // Context cache used for loading pointer resources.
-    private Context mDisplayContext;
+    private Context mPointerIconDisplayContext;
 
     private final File mDoubleTouchGestureEnableFile;
 
@@ -839,21 +839,31 @@
             throw new IllegalArgumentException("mode is invalid");
         }
         if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
-            if (event instanceof MotionEvent) {
-                final Context dispCtx = getContextForDisplay(event.getDisplayId());
-                final Display display = dispCtx.getDisplay();
+            // Motion events that are pointer events or relative mouse events will need to have the
+            // inverse display rotation applied to them.
+            if (event instanceof MotionEvent
+                    && (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
+                    || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE))) {
+                Context displayContext = getContextForDisplay(event.getDisplayId());
+                if (displayContext == null) {
+                    displayContext = Objects.requireNonNull(
+                            getContextForDisplay(Display.DEFAULT_DISPLAY));
+                }
+                final Display display = displayContext.getDisplay();
                 final int rotation = display.getRotation();
                 if (rotation != ROTATION_0) {
                     final MotionEvent motion = (MotionEvent) event;
                     // Injections are currently expected to be in the space of the injector (ie.
-                    // usually assumed to be post-rotated). Thus we need to unrotate into raw
+                    // usually assumed to be post-rotated). Thus we need to un-rotate into raw
                     // input coordinates for dispatch.
                     final Point sz = new Point();
-                    display.getRealSize(sz);
-                    if ((rotation % 2) != 0) {
-                        final int tmpX = sz.x;
-                        sz.x = sz.y;
-                        sz.y = tmpX;
+                    if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+                        display.getRealSize(sz);
+                        if ((rotation % 2) != 0) {
+                            final int tmpX = sz.x;
+                            sz.x = sz.y;
+                            sz.y = tmpX;
+                        }
                     }
                     motion.applyTransform(MotionEvent.createRotateMatrix(
                             (4 - rotation), sz.x, sz.y));
@@ -1742,6 +1752,11 @@
 
     /** Clean up input window handles of the given display. */
     public void onDisplayRemoved(int displayId) {
+        if (mPointerIconDisplayContext != null
+                && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
+            mPointerIconDisplayContext = null;
+        }
+
         nativeDisplayRemoved(mPtr, displayId);
     }
 
@@ -2969,24 +2984,43 @@
 
     // Native callback.
     private PointerIcon getPointerIcon(int displayId) {
-        return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
+        return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
     }
 
-    private Context getContextForDisplay(int displayId) {
-        if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
-            return mDisplayContext;
-        }
-
-        if (mContext.getDisplay().getDisplayId() == displayId) {
-            mDisplayContext = mContext;
-            return mDisplayContext;
+    @NonNull
+    private Context getContextForPointerIcon(int displayId) {
+        if (mPointerIconDisplayContext != null
+                && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
+            return mPointerIconDisplayContext;
         }
 
         // Create and cache context for non-default display.
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        mPointerIconDisplayContext = getContextForDisplay(displayId);
+
+        // Fall back to default display if the requested displayId does not exist.
+        if (mPointerIconDisplayContext == null) {
+            mPointerIconDisplayContext = getContextForDisplay(Display.DEFAULT_DISPLAY);
+        }
+        return mPointerIconDisplayContext;
+    }
+
+    @Nullable
+    private Context getContextForDisplay(int displayId) {
+        if (displayId == Display.INVALID_DISPLAY) {
+            return null;
+        }
+        if (mContext.getDisplay().getDisplayId() == displayId) {
+            return mContext;
+        }
+
+        final DisplayManager displayManager = Objects.requireNonNull(
+                mContext.getSystemService(DisplayManager.class));
         final Display display = displayManager.getDisplay(displayId);
-        mDisplayContext = mContext.createDisplayContext(display);
-        return mDisplayContext;
+        if (display == null) {
+            return null;
+        }
+
+        return mContext.createDisplayContext(display);
     }
 
     // Native callback.
@@ -3228,7 +3262,7 @@
      * Interface for the system to handle request from InputMonitors.
      */
     private final class InputMonitorHost extends IInputMonitorHost.Stub {
-        private final IBinder mToken;
+        private IBinder mToken;
 
         InputMonitorHost(IBinder token) {
             mToken = token;
@@ -3236,12 +3270,23 @@
 
         @Override
         public void pilferPointers() {
+            if (mToken == null) {
+                throw new IllegalStateException(
+                        "Illegal call to pilferPointers after InputMonitorHost is disposed.");
+            }
             nativePilferPointers(mPtr, mToken);
         }
 
         @Override
         public void dispose() {
-            nativeRemoveInputChannel(mPtr, mToken);
+            // We do not remove the input monitor here by calling nativeRemoveInputChannel because
+            // it causes a race in InputDispatcher between the removal of the InputChannel through
+            // that call and the InputChannel#dispose call (which causes an FD hangup) from the
+            // client (b/189135695).
+            //
+            // NOTE: This means the client is responsible for properly closing the InputMonitor by
+            // disposing the InputChannel and all its duplicates.
+            mToken = null;
         }
     }
 
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 720be82..29aa2a8 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -313,8 +313,13 @@
 
         injectKeyEvent(event);
         if (longpress) {
+            try {
+                Thread.sleep(ViewConfiguration.getLongPressTimeout());
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
             // Some long press behavior would check the event time, we set a new event time here.
-            final long nextEventTime = now + ViewConfiguration.getGlobalActionKeyTimeout();
+            final long nextEventTime = now + ViewConfiguration.getLongPressTimeout();
             injectKeyEvent(KeyEvent.changeTimeRepeat(event, nextEventTime, 1 /* repeatCount */,
                     KeyEvent.FLAG_LONG_PRESS));
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 9d80b9c..2328dfc 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -116,8 +116,10 @@
      *
      * @param windowToken the window token that is now in control, or {@code null} if no client
      *                   window is in control of the IME.
+     * @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent
+     *                         will end up to change later, or {@code false} otherwise.
      */
-    public abstract void reportImeControl(@Nullable IBinder windowToken);
+    public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged);
 
     /**
      * Destroys the IME surface.
@@ -176,7 +178,8 @@
                 }
 
                 @Override
-                public void reportImeControl(@Nullable IBinder windowToken) {
+                public void reportImeControl(@Nullable IBinder windowToken,
+                        boolean imeParentChanged) {
                 }
 
                 @Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 50d5b66..35c0e9a 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.internal.inputmethod.IInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.IVoidResultCallback;
 import com.android.internal.inputmethod.ImeTracing;
+import com.android.internal.inputmethod.InputBindResult;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.inputmethod.StartInputFlags;
@@ -179,7 +180,6 @@
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.InlineSuggestionsRequestInfo;
-import com.android.internal.view.InputBindResult;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -4934,13 +4934,19 @@
         return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
     }
 
-    private void reportImeControl(@Nullable IBinder windowToken) {
+    private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
         synchronized (mMethodMap) {
             if (mCurFocusedWindow != windowToken) {
                 // mCurPerceptible was set by the focused window, but it is no longer in control,
                 // so we reset mCurPerceptible.
                 mCurPerceptible = true;
             }
+            if (imeParentChanged) {
+                // Hide the IME method menu earlier when the IME surface parent will change in
+                // case seeing the dialog dismiss flickering during the next focused window
+                // starting the input connection.
+                mMenuController.hideInputMethodMenu();
+            }
         }
     }
 
@@ -4998,8 +5004,8 @@
         }
 
         @Override
-        public void reportImeControl(@Nullable IBinder windowToken) {
-            mService.reportImeControl(windowToken);
+        public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
+            mService.reportImeControl(windowToken, imeParentChanged);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index bebe6ed..91f14de 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -293,7 +293,7 @@
                             + ": brightness=" + brightness);
                     return;
                 }
-                int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness, null);
+                int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness);
                 int color = brightnessInt & 0x000000ff;
                 color = 0xff000000 | (color << 16) | (color << 8) | color;
                 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index dc3596b..57a7620 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -56,7 +56,7 @@
 
     private GeocoderProxy(Context context) {
         mServiceWatcher = ServiceWatcher.create(context, "GeocoderProxy",
-                new CurrentUserServiceSupplier(context, SERVICE_ACTION,
+                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
                         com.android.internal.R.bool.config_enableGeocoderOverlay,
                         com.android.internal.R.string.config_geocoderProviderPackageName),
                 null);
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index 6ac6e77..f63ba58 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -73,8 +73,8 @@
 
         mServiceWatcher = ServiceWatcher.create(context,
                 "HardwareActivityRecognitionProxy",
-                new CurrentUserServiceSupplier(context, SERVICE_ACTION, useOverlayResId,
-                        nonOverlayPackageResId),
+                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
+                        useOverlayResId, nonOverlayPackageResId),
                 this);
     }
 
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index 90b446e..d0e8dcf 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -67,7 +67,7 @@
         mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence);
         mServiceWatcher = ServiceWatcher.create(context,
                 "GeofenceProxy",
-                new CurrentUserServiceSupplier(context, SERVICE_ACTION,
+                CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
                         com.android.internal.R.bool.config_enableGeofenceOverlay,
                         com.android.internal.R.string.config_geofenceProviderPackageName),
                 this);
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index a9641f0..2b3f4207 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -103,7 +103,7 @@
 
         mContext = context;
         mServiceWatcher = ServiceWatcher.create(context, provider,
-                new CurrentUserServiceSupplier(context, action, enableOverlayResId,
+                CurrentUserServiceSupplier.createFromConfig(context, action, enableOverlayResId,
                         nonOverlayPackageResId), this);
         mName = provider;
 
diff --git a/services/core/java/com/android/server/media/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java
index a4f11b2..5fa2b1c 100644
--- a/services/core/java/com/android/server/media/MediaServerUtils.java
+++ b/services/core/java/com/android/server/media/MediaServerUtils.java
@@ -18,9 +18,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioPlaybackConfiguration;
 import android.os.Binder;
 
 import java.io.PrintWriter;
@@ -32,7 +29,7 @@
     /**
      * Verify that caller holds {@link android.Manifest.permission#DUMP}.
      */
-    static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
         if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             pw.println("Permission Denial: can't dump " + tag + " from from pid="
@@ -43,18 +40,4 @@
             return true;
         }
     }
-
-    /**
-     * Whether the given stream is currently active or not.
-     */
-    static boolean isStreamActive(AudioManager audioManager, int stream) {
-        for (AudioPlaybackConfiguration configuration
-                : audioManager.getActivePlaybackConfigurations()) {
-            AudioAttributes attributes = configuration.getAudioAttributes();
-            if (attributes != null && attributes.getVolumeControlStream() == stream) {
-                return configuration.isActive();
-            }
-        }
-        return false;
-    }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index abcf4fb..1525cd4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,6 +24,7 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.AudioSystem;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -515,7 +516,7 @@
             public void run() {
                 try {
                     if (useSuggested) {
-                        if (MediaServerUtils.isStreamActive(mAudioManager, stream)) {
+                        if (AudioSystem.isStreamActive(stream, 0)) {
                             mAudioManager.adjustSuggestedStreamVolumeForUid(stream,
                                     direction, flags, opPackageName, uid, pid,
                                     mContext.getApplicationInfo().targetSdkVersion);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9aaa577..bff7e52 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -42,6 +42,7 @@
 import android.content.pm.PackageManager;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
+import android.media.AudioSystem;
 import android.media.IRemoteSessionCallback;
 import android.media.MediaCommunicationManager;
 import android.media.Session2Token;
@@ -1236,15 +1237,19 @@
         }
 
         @Override
-        public MediaSession.Token getMediaKeyEventSession() {
+        public MediaSession.Token getMediaKeyEventSession(ComponentName notificationListener) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+            final int userId = userHandle.getIdentifier();
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!hasMediaControlPermission(pid, uid)) {
-                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + " get the media key event session");
+                if (!hasMediaControlPermission(pid, uid)
+                        && !isEnabledNotificationListener(
+                                notificationListener, userHandle, userId)) {
+                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission or an enabled"
+                            + " notification listener is required to"
+                            + " get media key event session.");
                 }
                 MediaSessionRecordImpl record;
                 synchronized (mLock) {
@@ -1267,15 +1272,19 @@
         }
 
         @Override
-        public String getMediaKeyEventSessionPackageName() {
+        public String getMediaKeyEventSessionPackageName(ComponentName notificationListener) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+            final int userId = userHandle.getIdentifier();
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!hasMediaControlPermission(pid, uid)) {
-                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + " get the media key event session package");
+                if (!hasMediaControlPermission(pid, uid)
+                        && !isEnabledNotificationListener(
+                        notificationListener, userHandle, userId)) {
+                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission or an enabled"
+                            + " notification listener is required to"
+                            + " get media key event session package name");
                 }
                 MediaSessionRecordImpl record;
                 synchronized (mLock) {
@@ -1587,19 +1596,25 @@
 
         @Override
         public void addOnMediaKeyEventSessionChangedListener(
-                final IOnMediaKeyEventSessionChangedListener listener) {
+                final IOnMediaKeyEventSessionChangedListener listener,
+                final ComponentName notificationListener) {
             if (listener == null) {
-                Log.w(TAG, "addOnMediaKeyEventSessionChangedListener: lister is null, ignoring");
+                Log.w(TAG, "addOnMediaKeyEventSessionChangedListener: listener is null, ignoring");
                 return;
             }
+
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
-            final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            final UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+            final int userId = userHandle.getIdentifier();
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!hasMediaControlPermission(pid, uid)) {
-                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + "  add MediaKeyEventSessionChangedListener");
+                if (!hasMediaControlPermission(pid, uid)
+                        && !isEnabledNotificationListener(
+                                notificationListener, userHandle, userId)) {
+                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission or an enabled"
+                            + " notification listener is required to"
+                            + " add MediaKeyEventSessionChangedListener.");
                 }
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
@@ -1621,18 +1636,16 @@
         public void removeOnMediaKeyEventSessionChangedListener(
                 final IOnMediaKeyEventSessionChangedListener listener) {
             if (listener == null) {
-                Log.w(TAG, "removeOnMediaKeyEventSessionChangedListener: lister is null, ignoring");
+                Log.w(TAG, "removeOnMediaKeyEventSessionChangedListener: listener is null,"
+                        + " ignoring");
                 return;
             }
+
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
             final long token = Binder.clearCallingIdentity();
             try {
-                if (!hasMediaControlPermission(pid, uid)) {
-                    throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
-                            + "  remove MediaKeyEventSessionChangedListener");
-                }
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
                     if (user == null || user.mFullUserId != userId) {
@@ -2172,7 +2185,7 @@
 
             boolean preferSuggestedStream = false;
             if (isValidLocalStreamType(suggestedStream)
-                    && MediaServerUtils.isStreamActive(mAudioManager, suggestedStream)) {
+                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
                 preferSuggestedStream = true;
             }
             if (session == null || preferSuggestedStream) {
@@ -2181,8 +2194,7 @@
                             + ". flags=" + flags + ", preferSuggestedStream="
                             + preferSuggestedStream + ", session=" + session);
                 }
-                if (musicOnly && !MediaServerUtils.isStreamActive(mAudioManager,
-                        AudioManager.STREAM_MUSIC)) {
+                if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
                     if (DEBUG_KEY_EVENT) {
                         Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
                                 + " flags=" + flags);
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 50eed19..c4c21df 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -325,7 +325,8 @@
         int size = records.size();
         for (int i = 0; i < size; i++) {
             MediaSessionRecord record = records.get(i);
-            if (record.checkPlaybackActiveState(true)) {
+            // Do not send the volume key events to remote sessions.
+            if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) {
                 mCachedVolumeDefault = record;
                 return record;
             }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4ee867b..097b071 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -289,8 +289,7 @@
     private String mActiveIface;
 
     /** Set of any ifaces associated with mobile networks since boot. */
-    @GuardedBy("mStatsLock")
-    private String[] mMobileIfaces = new String[0];
+    private volatile String[] mMobileIfaces = new String[0];
 
     /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
     @GuardedBy("mStatsLock")
@@ -935,7 +934,12 @@
 
     @Override
     public String[] getMobileIfaces() {
-        return mMobileIfaces;
+        // TODO (b/192758557): Remove debug log.
+        if (ArrayUtils.contains(mMobileIfaces, null)) {
+            throw new NullPointerException(
+                    "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+        }
+        return mMobileIfaces.clone();
     }
 
     @Override
@@ -1084,7 +1088,8 @@
     }
 
     @Override
-    public long getIfaceStats(String iface, int type) {
+    public long getIfaceStats(@NonNull String iface, int type) {
+        Objects.requireNonNull(iface);
         long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
         if (nativeIfaceStats == -1) {
             return nativeIfaceStats;
@@ -1382,7 +1387,12 @@
             }
         }
 
-        mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
+        mMobileIfaces = mobileIfaces.toArray(new String[0]);
+        // TODO (b/192758557): Remove debug log.
+        if (ArrayUtils.contains(mMobileIfaces, null)) {
+            throw new NullPointerException(
+                    "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+        }
     }
 
     private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 74ef4ca..5ffb754 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4365,8 +4365,7 @@
                             final int userId = r.getSbn().getUserId();
                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
                                     !mUserProfiles.isCurrentProfile(userId)) {
-                                throw new SecurityException("Disallowed call from listener: "
-                                        + info.service);
+                                continue;
                             }
                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
                                     r.getSbn().getPackageName(), r.getSbn().getTag(),
@@ -4433,8 +4432,7 @@
                         final int userId = r.getSbn().getUserId();
                         if (userId != info.userid && userId != UserHandle.USER_ALL
                                 && !mUserProfiles.isCurrentProfile(userId)) {
-                            throw new SecurityException("Disallowed call from listener: "
-                                    + info.service);
+                            continue;
                         }
                         seen.add(r);
                         if (!r.isSeen()) {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 6ae4dd0..7889ff2 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -250,6 +250,14 @@
             throws PackageManagerException;
 
     /**
+     * Returns {@code ApeInfo} about apex sessions that have been marked ready via
+     * {@link #markStagedSessionReady(int)}
+     *
+     * Returns empty array if there is no staged apex session or if there is any error.
+     */
+    abstract ApexInfo[] getStagedApexInfos(ApexSessionParams params);
+
+    /**
      * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
      * applied at next reboot.
      *
@@ -758,6 +766,19 @@
         }
 
         @Override
+        ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
+            try {
+                return waitForApexService().getStagedApexInfos(params);
+            } catch (RemoteException re) {
+                Slog.w(TAG, "Unable to contact apexservice" + re.getMessage());
+                throw new RuntimeException(re);
+            } catch (Exception e) {
+                Slog.w(TAG, "Failed to collect staged apex infos" + e.getMessage());
+                return new ApexInfo[0];
+            }
+        }
+
+        @Override
         void markStagedSessionReady(int sessionId) throws PackageManagerException {
             try {
                 waitForApexService().markStagedSessionReady(sessionId);
@@ -1250,6 +1271,11 @@
         }
 
         @Override
+        ApexInfo[] getStagedApexInfos(ApexSessionParams params) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
         void markStagedSessionReady(int sessionId) {
             throw new UnsupportedOperationException();
         }
diff --git a/services/core/java/com/android/server/pm/CommitRequest.java b/services/core/java/com/android/server/pm/CommitRequest.java
new file mode 100644
index 0000000..d1a6002
--- /dev/null
+++ b/services/core/java/com/android/server/pm/CommitRequest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+
+import java.util.Map;
+
+/**
+ * Package state to commit to memory and disk after reconciliation has completed.
+ */
+final class CommitRequest {
+    final Map<String, ReconciledPackage> mReconciledPackages;
+    @NonNull final int[] mAllUsers;
+
+    CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
+            @NonNull int[] allUsers) {
+        mReconciledPackages = reconciledPackages;
+        mAllUsers = allUsers;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/DeletePackageAction.java b/services/core/java/com/android/server/pm/DeletePackageAction.java
new file mode 100644
index 0000000..8ef6601
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DeletePackageAction.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.UserHandle;
+
+final class DeletePackageAction {
+    public final PackageSetting mDeletingPs;
+    public final PackageSetting mDisabledPs;
+    public final PackageRemovedInfo mRemovedInfo;
+    public final int mFlags;
+    public final UserHandle mUser;
+
+    DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
+            PackageRemovedInfo removedInfo, int flags, UserHandle user) {
+        mDeletingPs = deletingPs;
+        mDisabledPs = disabledPs;
+        mRemovedInfo = removedInfo;
+        mFlags = flags;
+        mUser = user;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java
new file mode 100644
index 0000000..3e18374
--- /dev/null
+++ b/services/core/java/com/android/server/pm/FileInstallArgs.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.content.pm.PackageManager.INSTALL_STAGED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
+
+import android.content.pm.DataLoaderType;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.SELinux;
+import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logic to handle installation of new applications, including copying
+ * and renaming logic.
+ */
+class FileInstallArgs extends InstallArgs {
+    private File mCodeFile;
+
+    // Example topology:
+    // /data/app/com.example/base.apk
+    // /data/app/com.example/split_foo.apk
+    // /data/app/com.example/lib/arm/libfoo.so
+    // /data/app/com.example/lib/arm64/libfoo.so
+    // /data/app/com.example/dalvik/arm/base.apk@classes.dex
+
+    /** New install */
+    FileInstallArgs(InstallParams params) {
+        super(params);
+    }
+
+    /** Existing install */
+    FileInstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
+        super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
+                null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
+                SigningDetails.UNKNOWN,
+                PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
+                false, DataLoaderType.NONE, pm);
+        mCodeFile = (codePath != null) ? new File(codePath) : null;
+    }
+
+    int copyApk() {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
+        try {
+            return doCopyApk();
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    private int doCopyApk() {
+        if (mOriginInfo.mStaged) {
+            if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
+            mCodeFile = mOriginInfo.mFile;
+            return PackageManager.INSTALL_SUCCEEDED;
+        }
+
+        try {
+            final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+            final File tempDir =
+                    mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
+            mCodeFile = tempDir;
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to create copy file: " + e);
+            return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+        }
+
+        int ret = PackageManagerServiceUtils.copyPackage(
+                mOriginInfo.mFile.getAbsolutePath(), mCodeFile);
+        if (ret != PackageManager.INSTALL_SUCCEEDED) {
+            Slog.e(TAG, "Failed to copy package");
+            return ret;
+        }
+
+        final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
+        final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
+        NativeLibraryHelper.Handle handle = null;
+        try {
+            handle = NativeLibraryHelper.Handle.create(mCodeFile);
+            ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
+                    mAbiOverride, isIncremental);
+        } catch (IOException e) {
+            Slog.e(TAG, "Copying native libraries failed", e);
+            ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+        } finally {
+            IoUtils.closeQuietly(handle);
+        }
+
+        return ret;
+    }
+
+    int doPreInstall(int status) {
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp();
+        }
+        return status;
+    }
+
+    @Override
+    boolean doRename(int status, ParsedPackage parsedPackage) {
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp();
+            return false;
+        }
+
+        final File targetDir = resolveTargetDir();
+        final File beforeCodeFile = mCodeFile;
+        final File afterCodeFile = PackageManagerService.getNextCodePath(targetDir,
+                parsedPackage.getPackageName());
+
+        if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+        final boolean onIncremental = mPm.mIncrementalManager != null
+                && isIncrementalPath(beforeCodeFile.getAbsolutePath());
+        try {
+            makeDirRecursive(afterCodeFile.getParentFile(), 0775);
+            if (onIncremental) {
+                // Just link files here. The stage dir will be removed when the installation
+                // session is completed.
+                mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
+            } else {
+                Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+            }
+        } catch (IOException | ErrnoException e) {
+            Slog.w(TAG, "Failed to rename", e);
+            return false;
+        }
+
+        if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
+            Slog.w(TAG, "Failed to restorecon");
+            return false;
+        }
+
+        // Reflect the rename internally
+        mCodeFile = afterCodeFile;
+
+        // Reflect the rename in scanned details
+        try {
+            parsedPackage.setPath(afterCodeFile.getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
+            return false;
+        }
+        parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
+                afterCodeFile, parsedPackage.getBaseApkPath()));
+        parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
+                afterCodeFile, parsedPackage.getSplitCodePaths()));
+
+        return true;
+    }
+
+    // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
+    //  flow, we won't need this method anymore.
+    private File resolveTargetDir() {
+        boolean isStagedInstall = (mInstallFlags & INSTALL_STAGED) != 0;
+        if (isStagedInstall) {
+            return Environment.getDataAppDirectory(null);
+        } else {
+            return mCodeFile.getParentFile();
+        }
+    }
+
+    int doPostInstall(int status, int uid) {
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp();
+        }
+        return status;
+    }
+
+    @Override
+    String getCodePath() {
+        return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
+    }
+
+    private boolean cleanUp() {
+        if (mCodeFile == null || !mCodeFile.exists()) {
+            return false;
+        }
+        mPm.removeCodePathLI(mCodeFile);
+        return true;
+    }
+
+    void cleanUpResourcesLI() {
+        // Try enumerating all code paths before deleting
+        List<String> allCodePaths = Collections.EMPTY_LIST;
+        if (mCodeFile != null && mCodeFile.exists()) {
+            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
+                    input.reset(), mCodeFile, /* flags */ 0);
+            if (result.isSuccess()) {
+                // Ignore error; we tried our best
+                allCodePaths = result.getResult().getAllApkPaths();
+            }
+        }
+
+        cleanUp();
+        removeDexFiles(allCodePaths, mInstructionSets);
+    }
+
+    void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+        if (!allCodePaths.isEmpty()) {
+            if (instructionSets == null) {
+                throw new IllegalStateException("instructionSet == null");
+            }
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String codePath : allCodePaths) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                    try {
+                        mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet);
+                    } catch (Installer.InstallerException ignored) {
+                    }
+                }
+            }
+        }
+    }
+
+    boolean doPostDeleteLI(boolean delete) {
+        // XXX err, shouldn't we respect the delete flag?
+        cleanUpResourcesLI();
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java
new file mode 100644
index 0000000..b8c2eb8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/HandlerParams.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.UserHandle;
+import android.util.Slog;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+abstract class HandlerParams {
+    /** User handle for the user requesting the information or installation. */
+    private final UserHandle mUser;
+    String mTraceMethod;
+    int mTraceCookie;
+
+    HandlerParams(UserHandle user) {
+        mUser = user;
+    }
+
+    UserHandle getUser() {
+        return mUser;
+    }
+
+    HandlerParams setTraceMethod(String traceMethod) {
+        mTraceMethod = traceMethod;
+        return this;
+    }
+
+    HandlerParams setTraceCookie(int traceCookie) {
+        mTraceCookie = traceCookie;
+        return this;
+    }
+
+    final void startCopy() {
+        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
+        handleStartCopy();
+        handleReturnCode();
+    }
+
+    abstract void handleStartCopy();
+    abstract void handleReturnCode();
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
new file mode 100644
index 0000000..bb797cb
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.IPackageLoadingProgressCallback;
+
+/**
+ * Loading progress callback, used to listen for progress changes and update package setting
+ */
+final class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
+    private final String mPackageName;
+    private final PackageManagerService mPm;
+    IncrementalProgressListener(String packageName, PackageManagerService pm) {
+        mPackageName = packageName;
+        mPm = pm;
+    }
+
+    @Override
+    public void onPackageLoadingProgressChanged(float progress) {
+        final PackageSetting ps;
+        synchronized (mPm.mLock) {
+            ps = mPm.mSettings.getPackageLPr(mPackageName);
+            if (ps == null) {
+                return;
+            }
+            ps.setLoadingProgress(progress);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index 7627281..3101ca7 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -118,12 +118,19 @@
      * @param progress Value between [0, 1].
      */
     public void setProgress(float progress) {
+        final boolean oldLoadingState;
         final boolean newLoadingState;
         synchronized (mLock) {
-            updateProgressLocked(progress);
+            oldLoadingState = mLoadingState.isLoading();
+            if (oldLoadingState) {
+                // Due to asynchronous progress reporting, incomplete progress might be received
+                // after the app is migrated off incremental. Ignore such progress updates.
+                updateProgressLocked(progress);
+            }
             newLoadingState = mLoadingState.isLoading();
         }
-        if (!newLoadingState) {
+        if (oldLoadingState && !newLoadingState) {
+            // Only report the state change when loading state changes from true to false
             onLoadingStateChanged();
         }
     }
diff --git a/services/core/java/com/android/server/pm/IncrementalStatesCallback.java b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java
new file mode 100644
index 0000000..478c99b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+/**
+ * Package states callback, used to listen for package state changes and send broadcasts
+ */
+final class IncrementalStatesCallback implements IncrementalStates.Callback {
+    private final String mPackageName;
+    private final PackageManagerService mPm;
+
+    IncrementalStatesCallback(String packageName, PackageManagerService pm) {
+        mPackageName = packageName;
+        mPm = pm;
+    }
+
+    @Override
+    public void onPackageFullyLoaded() {
+        final String codePath;
+        synchronized (mPm.mLock) {
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(mPackageName);
+            if (ps == null) {
+                return;
+            }
+            codePath = ps.getPathString();
+        }
+        // Unregister progress listener
+        mPm.mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
+        // Make sure the information is preserved
+        mPm.scheduleWriteSettingsLocked();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
new file mode 100644
index 0000000..07c7123
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageManager;
+import android.content.pm.SigningDetails;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.util.List;
+
+abstract class InstallArgs {
+    /** @see InstallParams#mOriginInfo */
+    final OriginInfo mOriginInfo;
+    /** @see InstallParams#mMoveInfo */
+    final MoveInfo mMoveInfo;
+
+    final IPackageInstallObserver2 mObserver;
+    // Always refers to PackageManager flags only
+    final int mInstallFlags;
+    @NonNull
+    final InstallSource mInstallSource;
+    final String mVolumeUuid;
+    final UserHandle mUser;
+    final String mAbiOverride;
+    final String[] mInstallGrantPermissions;
+    final List<String> mAllowlistedRestrictedPermissions;
+    final int mAutoRevokePermissionsMode;
+    /** If non-null, drop an async trace when the install completes */
+    final String mTraceMethod;
+    final int mTraceCookie;
+    final SigningDetails mSigningDetails;
+    final int mInstallReason;
+    final int mInstallScenario;
+    final boolean mForceQueryableOverride;
+    final int mDataLoaderType;
+
+    // The list of instruction sets supported by this app. This is currently
+    // only used during the rmdex() phase to clean up resources. We can get rid of this
+    // if we move dex files under the common app path.
+    @Nullable String[] mInstructionSets;
+
+    @NonNull final PackageManagerService mPm;
+
+    InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
+            int installFlags, InstallSource installSource, String volumeUuid,
+            UserHandle user, String[] instructionSets,
+            String abiOverride, String[] installGrantPermissions,
+            List<String> allowlistedRestrictedPermissions,
+            int autoRevokePermissionsMode,
+            String traceMethod, int traceCookie, SigningDetails signingDetails,
+            int installReason, int installScenario, boolean forceQueryableOverride,
+            int dataLoaderType, PackageManagerService pm) {
+        mOriginInfo = originInfo;
+        mMoveInfo = moveInfo;
+        mInstallFlags = installFlags;
+        mObserver = observer;
+        mInstallSource = Preconditions.checkNotNull(installSource);
+        mVolumeUuid = volumeUuid;
+        mUser = user;
+        mInstructionSets = instructionSets;
+        mAbiOverride = abiOverride;
+        mInstallGrantPermissions = installGrantPermissions;
+        mAllowlistedRestrictedPermissions = allowlistedRestrictedPermissions;
+        mAutoRevokePermissionsMode = autoRevokePermissionsMode;
+        mTraceMethod = traceMethod;
+        mTraceCookie = traceCookie;
+        mSigningDetails = signingDetails;
+        mInstallReason = installReason;
+        mInstallScenario = installScenario;
+        mForceQueryableOverride = forceQueryableOverride;
+        mDataLoaderType = dataLoaderType;
+        mPm = pm;
+    }
+
+    /** New install */
+    InstallArgs(InstallParams params) {
+        this(params.mOriginInfo, params.mMoveInfo, params.mObserver, params.mInstallFlags,
+                params.mInstallSource, params.mVolumeUuid,
+                params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
+                params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
+                params.mAutoRevokePermissionsMode,
+                params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
+                params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
+                params.mDataLoaderType, params.mPm);
+    }
+
+    abstract int copyApk();
+    abstract int doPreInstall(int status);
+
+    /**
+     * Rename package into final resting place. All paths on the given
+     * scanned package should be updated to reflect the rename.
+     */
+    abstract boolean doRename(int status, ParsedPackage parsedPackage);
+    abstract int doPostInstall(int status, int uid);
+
+    /** @see PackageSettingBase#getPath() */
+    abstract String getCodePath();
+
+    // Need installer lock especially for dex file removal.
+    abstract void cleanUpResourcesLI();
+    abstract boolean doPostDeleteLI(boolean delete);
+
+    /**
+     * Called before the source arguments are copied. This is used mostly
+     * for MoveParams when it needs to read the source file to put it in the
+     * destination.
+     */
+    int doPreCopy() {
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+
+    /**
+     * Called after the source arguments are copied. This is used mostly for
+     * MoveParams when it needs to read the source file to put it in the
+     * destination.
+     */
+    int doPostCopy(int uid) {
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+
+    protected boolean isEphemeral() {
+        return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+    }
+
+    UserHandle getUser() {
+        return mUser;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java
new file mode 100644
index 0000000..45ce3980
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstallParams.java
@@ -0,0 +1,2162 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
+import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
+import static android.content.pm.PackageManager.INSTALL_STAGED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT;
+import static com.android.server.pm.PackageManagerService.INIT_COPY;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.PRECOMPILE_LAYOUTS;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD;
+import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
+import static com.android.server.pm.PackageManagerService.SCAN_MOVE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
+import static com.android.server.pm.PackageManagerService.SCAN_UPDATE_SIGNATURE;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
+import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ApplicationPackageManager;
+import android.content.pm.DataLoaderType;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageChangeEvent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.component.ParsedPermission;
+import android.content.pm.parsing.component.ParsedPermissionGroup;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.F2fsUtils;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.security.VerityUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.Watchdog;
+import com.android.server.pm.dex.DexoptOptions;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.Permission;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+final class InstallParams extends HandlerParams {
+    final OriginInfo mOriginInfo;
+    final MoveInfo mMoveInfo;
+    final IPackageInstallObserver2 mObserver;
+    int mInstallFlags;
+    @NonNull
+    final InstallSource mInstallSource;
+    final String mVolumeUuid;
+    int mRet;
+    final String mPackageAbiOverride;
+    final String[] mGrantedRuntimePermissions;
+    final List<String> mAllowlistedRestrictedPermissions;
+    final int mAutoRevokePermissionsMode;
+    final SigningDetails mSigningDetails;
+    final int mInstallReason;
+    final int mInstallScenario;
+    @Nullable
+    MultiPackageInstallParams mParentInstallParams;
+    final boolean mForceQueryableOverride;
+    final int mDataLoaderType;
+    final long mRequiredInstalledVersionCode;
+    final PackageLite mPackageLite;
+    @NonNull final PackageManagerService mPm;
+
+    InstallParams(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
+            int installFlags, InstallSource installSource, String volumeUuid,
+            UserHandle user, String packageAbiOverride, PackageLite packageLite,
+            PackageManagerService pm) {
+        super(user);
+        mPm = pm;
+        mOriginInfo = originInfo;
+        mMoveInfo = moveInfo;
+        mObserver = observer;
+        mInstallFlags = installFlags;
+        mInstallSource = Preconditions.checkNotNull(installSource);
+        mVolumeUuid = volumeUuid;
+        mPackageAbiOverride = packageAbiOverride;
+
+        mGrantedRuntimePermissions = null;
+        mAllowlistedRestrictedPermissions = null;
+        mAutoRevokePermissionsMode = MODE_DEFAULT;
+        mSigningDetails = SigningDetails.UNKNOWN;
+        mInstallReason = PackageManager.INSTALL_REASON_UNKNOWN;
+        mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
+        mForceQueryableOverride = false;
+        mDataLoaderType = DataLoaderType.NONE;
+        mRequiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
+        mPackageLite = packageLite;
+    }
+
+    InstallParams(File stagedDir, IPackageInstallObserver2 observer,
+            PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+            UserHandle user, SigningDetails signingDetails, int installerUid,
+            PackageLite packageLite, PackageManagerService pm) {
+        super(user);
+        mPm = pm;
+        mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
+        mMoveInfo = null;
+        mInstallReason = fixUpInstallReason(
+                installSource.installerPackageName, installerUid, sessionParams.installReason);
+        mInstallScenario = sessionParams.installScenario;
+        mObserver = observer;
+        mInstallFlags = sessionParams.installFlags;
+        mInstallSource = installSource;
+        mVolumeUuid = sessionParams.volumeUuid;
+        mPackageAbiOverride = sessionParams.abiOverride;
+        mGrantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
+        mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
+        mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
+        mSigningDetails = signingDetails;
+        mForceQueryableOverride = sessionParams.forceQueryableOverride;
+        mDataLoaderType = (sessionParams.dataLoaderParams != null)
+                ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+        mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+        mPackageLite = packageLite;
+    }
+
+    @Override
+    public String toString() {
+        return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+                + " file=" + mOriginInfo.mFile + "}";
+    }
+
+    private int installLocationPolicy(PackageInfoLite pkgLite) {
+        String packageName = pkgLite.packageName;
+        int installLocation = pkgLite.installLocation;
+        // reader
+        synchronized (mPm.mLock) {
+            // Currently installed package which the new package is attempting to replace or
+            // null if no such package is installed.
+            AndroidPackage installedPkg = mPm.mPackages.get(packageName);
+
+            if (installedPkg != null) {
+                if ((mInstallFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+                    // Check for updated system application.
+                    if (installedPkg.isSystem()) {
+                        return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+                    } else {
+                        // If current upgrade specifies particular preference
+                        if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+                            // Application explicitly specified internal.
+                            return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+                        } else if (
+                                installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+                            // App explicitly prefers external. Let policy decide
+                        } else {
+                            // Prefer previous location
+                            if (installedPkg.isExternalStorage()) {
+                                return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
+                            }
+                            return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
+                        }
+                    }
+                } else {
+                    // Invalid install. Return error code
+                    return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
+                }
+            }
+        }
+        return pkgLite.recommendedInstallLocation;
+    }
+
+    /**
+     * Override install location based on default policy if needed.
+     *
+     * Only {@link #mInstallFlags} may mutate in this method.
+     *
+     * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in
+     * {@link #mInstallFlags}
+     */
+    private int overrideInstallLocation(PackageInfoLite pkgLite) {
+        final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+        if (DEBUG_INSTANT && ephemeral) {
+            Slog.v(TAG, "pkgLite for install: " + pkgLite);
+        }
+
+        if (mOriginInfo.mStaged) {
+            // If we're already staged, we've firmly committed to an install location
+            if (mOriginInfo.mFile != null) {
+                mInstallFlags |= PackageManager.INSTALL_INTERNAL;
+            } else {
+                throw new IllegalStateException("Invalid stage location");
+            }
+        } else if (pkgLite.recommendedInstallLocation
+                == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+            /*
+             * If we are not staged and have too little free space, try to free cache
+             * before giving up.
+             */
+            // TODO: focus freeing disk space on the target device
+            final StorageManager storage = StorageManager.from(mPm.mContext);
+            final long lowThreshold = storage.getStorageLowBytes(
+                    Environment.getDataDirectory());
+
+            final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
+                    mOriginInfo.mResolvedPath, mPackageAbiOverride);
+            if (sizeBytes >= 0) {
+                try {
+                    mPm.mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
+                    pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+                            mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags,
+                            mPackageAbiOverride);
+                } catch (Installer.InstallerException e) {
+                    Slog.w(TAG, "Failed to free cache", e);
+                }
+            }
+
+            /*
+             * The cache free must have deleted the file we downloaded to install.
+             *
+             * TODO: fix the "freeCache" call to not delete the file we care about.
+             */
+            if (pkgLite.recommendedInstallLocation
+                    == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+                pkgLite.recommendedInstallLocation =
+                        PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
+            }
+        }
+
+        int ret = INSTALL_SUCCEEDED;
+        int loc = pkgLite.recommendedInstallLocation;
+        if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
+            ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+        } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
+            ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+        } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+            ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+            ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+        } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+            ret = PackageManager.INSTALL_FAILED_INVALID_URI;
+        } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
+            ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+        } else {
+            // Override with defaults if needed.
+            loc = installLocationPolicy(pkgLite);
+
+            final boolean onInt = (mInstallFlags & PackageManager.INSTALL_INTERNAL) != 0;
+
+            if (!onInt) {
+                // Override install location with flags
+                if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+                    // Set the flag to install on external media.
+                    mInstallFlags &= ~PackageManager.INSTALL_INTERNAL;
+                } else {
+                    // Make sure the flag for installing on external
+                    // media is unset
+                    mInstallFlags |= PackageManager.INSTALL_INTERNAL;
+                }
+            }
+        }
+        return ret;
+    }
+
+    /*
+     * Invoke remote method to get package information and install
+     * location values. Override install location based on default
+     * policy if needed and then create install arguments based
+     * on the install location.
+     */
+    public void handleStartCopy() {
+        if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
+            mRet = INSTALL_SUCCEEDED;
+            return;
+        }
+        PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+                mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
+
+        // For staged session, there is a delay between its verification and install. Device
+        // state can change within this delay and hence we need to re-verify certain conditions.
+        boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
+        if (isStaged) {
+            Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+                    pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
+            mRet = ret.first;
+            if (mRet != INSTALL_SUCCEEDED) {
+                return;
+            }
+        }
+
+        mRet = overrideInstallLocation(pkgLite);
+    }
+
+    @Override
+    void handleReturnCode() {
+        processPendingInstall();
+    }
+
+    private void processPendingInstall() {
+        InstallArgs args = createInstallArgs(this);
+        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+            mRet = args.copyApk();
+        }
+        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+            F2fsUtils.releaseCompressedBlocks(
+                    mPm.mContext.getContentResolver(), new File(args.getCodePath()));
+        }
+        if (mParentInstallParams != null) {
+            mParentInstallParams.tryProcessInstallRequest(args, mRet);
+        } else {
+            PackageInstalledInfo res = new PackageInstalledInfo(mRet);
+            processInstallRequestsAsync(
+                    res.mReturnCode == PackageManager.INSTALL_SUCCEEDED,
+                    Collections.singletonList(new InstallRequest(args, res)));
+        }
+    }
+
+    private InstallArgs createInstallArgs(InstallParams params) {
+        if (params.mMoveInfo != null) {
+            return new MoveInstallArgs(params);
+        } else {
+            return new FileInstallArgs(params);
+        }
+    }
+
+    // Queue up an async operation since the package installation may take a little while.
+    private void processInstallRequestsAsync(boolean success,
+            List<InstallRequest> installRequests) {
+        mPm.mHandler.post(() -> {
+            List<InstallRequest> apexInstallRequests = new ArrayList<>();
+            List<InstallRequest> apkInstallRequests = new ArrayList<>();
+            for (InstallRequest request : installRequests) {
+                if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
+                    apexInstallRequests.add(request);
+                } else {
+                    apkInstallRequests.add(request);
+                }
+            }
+            // Note: supporting multi package install of both APEXes and APKs might requir some
+            // thinking to ensure atomicity of the install.
+            if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
+                // This should've been caught at the validation step, but for some reason wasn't.
+                throw new IllegalStateException(
+                        "Attempted to do a multi package install of both APEXes and APKs");
+            }
+            if (!apexInstallRequests.isEmpty()) {
+                if (success) {
+                    // Since installApexPackages requires talking to external service (apexd), we
+                    // schedule to run it async. Once it finishes, it will resume the install.
+                    Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
+                            "installApexPackages");
+                    t.start();
+                } else {
+                    // Non-staged APEX installation failed somewhere before
+                    // processInstallRequestAsync. In that case just notify the observer about the
+                    // failure.
+                    InstallRequest request = apexInstallRequests.get(0);
+                    mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
+                }
+                return;
+            }
+            if (success) {
+                for (InstallRequest request : apkInstallRequests) {
+                    request.mArgs.doPreInstall(request.mInstallResult.mReturnCode);
+                }
+                synchronized (mPm.mInstallLock) {
+                    installPackagesTracedLI(apkInstallRequests);
+                }
+                for (InstallRequest request : apkInstallRequests) {
+                    request.mArgs.doPostInstall(
+                            request.mInstallResult.mReturnCode, request.mInstallResult.mUid);
+                }
+            }
+            for (InstallRequest request : apkInstallRequests) {
+                mPm.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
+                        request.mInstallResult,
+                        new PackageManagerService.PostInstallData(request.mArgs,
+                                request.mInstallResult, null));
+            }
+        });
+    }
+
+    private void installApexPackagesTraced(List<InstallRequest> requests) {
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages");
+            installApexPackages(requests);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    private void installApexPackages(List<InstallRequest> requests) {
+        if (requests.isEmpty()) {
+            return;
+        }
+        if (requests.size() != 1) {
+            throw new IllegalStateException(
+                    "Only a non-staged install of a single APEX is supported");
+        }
+        InstallRequest request = requests.get(0);
+        try {
+            // Should directory scanning logic be moved to ApexManager for better test coverage?
+            final File dir = request.mArgs.mOriginInfo.mResolvedFile;
+            final File[] apexes = dir.listFiles();
+            if (apexes == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        dir.getAbsolutePath() + " is not a directory");
+            }
+            if (apexes.length != 1) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Expected exactly one .apex file under " + dir.getAbsolutePath()
+                                + " got: " + apexes.length);
+            }
+            try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
+                mPm.mApexManager.installPackage(apexes[0], packageParser);
+            }
+        } catch (PackageManagerException e) {
+            request.mInstallResult.setError("APEX installation failed", e);
+        }
+        PackageManagerService.invalidatePackageInfoCache();
+        mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
+    }
+
+    @GuardedBy("mInstallLock")
+    private void installPackagesTracedLI(List<InstallRequest> requests) {
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
+            installPackagesLI(requests);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    /**
+     * Installs one or more packages atomically. This operation is broken up into four phases:
+     * <ul>
+     *     <li><b>Prepare</b>
+     *         <br/>Analyzes any current install state, parses the package and does initial
+     *         validation on it.</li>
+     *     <li><b>Scan</b>
+     *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
+     *     <li><b>Reconcile</b>
+     *         <br/>Validates scanned packages in the context of each other and the current system
+     *         state to ensure that the install will be successful.
+     *     <li><b>Commit</b>
+     *         <br/>Commits all scanned packages and updates system state. This is the only place
+     *         that system state may be modified in the install flow and all predictable errors
+     *         must be determined before this phase.</li>
+     * </ul>
+     *
+     * Failure at any phase will result in a full failure to install all packages.
+     */
+    @GuardedBy("mInstallLock")
+    private void installPackagesLI(List<InstallRequest> requests) {
+        final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
+        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
+        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
+        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
+        final Map<String, Settings.VersionInfo> versionInfos = new ArrayMap<>(requests.size());
+        final Map<String, PackageSetting> lastStaticSharedLibSettings =
+                new ArrayMap<>(requests.size());
+        final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
+        boolean success = false;
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
+            for (InstallRequest request : requests) {
+                // TODO(b/109941548): remove this once we've pulled everything from it and into
+                //                    scan, reconcile or commit.
+                final PrepareResult prepareResult;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
+                    prepareResult =
+                            preparePackageLI(request.mArgs, request.mInstallResult);
+                } catch (PrepareFailure prepareFailure) {
+                    request.mInstallResult.setError(prepareFailure.error,
+                            prepareFailure.getMessage());
+                    request.mInstallResult.mOrigPackage = prepareFailure.mConflictingPackage;
+                    request.mInstallResult.mOrigPermission = prepareFailure.mConflictingPermission;
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                request.mInstallResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                request.mInstallResult.mInstallerPackageName =
+                        request.mArgs.mInstallSource.installerPackageName;
+
+                final String packageName = prepareResult.mPackageToScan.getPackageName();
+                prepareResults.put(packageName, prepareResult);
+                installResults.put(packageName, request.mInstallResult);
+                installArgs.put(packageName, request.mArgs);
+                try {
+                    final ScanResult result = mPm.scanPackageTracedLI(
+                            prepareResult.mPackageToScan, prepareResult.mParseFlags,
+                            prepareResult.mScanFlags, System.currentTimeMillis(),
+                            request.mArgs.mUser, request.mArgs.mAbiOverride);
+                    if (null != preparedScans.put(result.mPkgSetting.pkg.getPackageName(),
+                            result)) {
+                        request.mInstallResult.setError(
+                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Duplicate package " + result.mPkgSetting.pkg.getPackageName()
+                                        + " in multi-package install request.");
+                        return;
+                    }
+                    createdAppId.put(packageName, mPm.optimisticallyRegisterAppId(result));
+                    versionInfos.put(result.mPkgSetting.pkg.getPackageName(),
+                            mPm.getSettingsVersionForPackage(result.mPkgSetting.pkg));
+                    if (result.mStaticSharedLibraryInfo != null) {
+                        final PackageSetting sharedLibLatestVersionSetting =
+                                mPm.getSharedLibLatestVersionSetting(result);
+                        if (sharedLibLatestVersionSetting != null) {
+                            lastStaticSharedLibSettings.put(result.mPkgSetting.pkg.getPackageName(),
+                                    sharedLibLatestVersionSetting);
+                        }
+                    }
+                } catch (PackageManagerException e) {
+                    request.mInstallResult.setError("Scanning Failed.", e);
+                    return;
+                }
+            }
+            ReconcileRequest
+                    reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
+                    installResults,
+                    prepareResults,
+                    mPm.mSharedLibraries,
+                    Collections.unmodifiableMap(mPm.mPackages), versionInfos,
+                    lastStaticSharedLibSettings);
+            CommitRequest commitRequest = null;
+            synchronized (mPm.mLock) {
+                Map<String, ReconciledPackage> reconciledPackages;
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
+                    reconciledPackages = PackageManagerService.reconcilePackagesLocked(
+                            reconcileRequest, mPm.mSettings.getKeySetManagerService(),
+                            mPm.mInjector);
+                } catch (ReconcileFailure e) {
+                    for (InstallRequest request : requests) {
+                        request.mInstallResult.setError("Reconciliation failed...", e);
+                    }
+                    return;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+                try {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
+                    commitRequest = new CommitRequest(reconciledPackages,
+                            mPm.mUserManager.getUserIds());
+                    commitPackagesLocked(commitRequest);
+                    success = true;
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            }
+            executePostCommitSteps(commitRequest);
+        } finally {
+            if (success) {
+                for (InstallRequest request : requests) {
+                    final InstallArgs args = request.mArgs;
+                    if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
+                        continue;
+                    }
+                    if (args.mSigningDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
+                        continue;
+                    }
+                    // For incremental installs, we bypass the verifier prior to install. Now
+                    // that we know the package is valid, send a notice to the verifier with
+                    // the root hash of the base.apk.
+                    final String baseCodePath = request.mInstallResult.mPkg.getBaseApkPath();
+                    final String[] splitCodePaths = request.mInstallResult.mPkg.getSplitCodePaths();
+                    final Uri originUri = Uri.fromFile(args.mOriginInfo.mResolvedFile);
+                    final int verificationId = mPm.mPendingVerificationToken++;
+                    final String rootHashString = PackageManagerServiceUtils
+                            .buildVerificationRootHashString(baseCodePath, splitCodePaths);
+                    mPm.broadcastPackageVerified(verificationId, originUri,
+                            PackageManager.VERIFICATION_ALLOW, rootHashString,
+                            args.mDataLoaderType, args.getUser());
+                }
+            } else {
+                for (ScanResult result : preparedScans.values()) {
+                    if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(),
+                            false)) {
+                        mPm.cleanUpAppIdCreation(result);
+                    }
+                }
+                // TODO(b/194319951): create a more descriptive reason than unknown
+                // mark all non-failure installs as UNKNOWN so we do not treat them as success
+                for (InstallRequest request : requests) {
+                    if (request.mInstallResult.mFreezer != null) {
+                        request.mInstallResult.mFreezer.close();
+                    }
+                    if (request.mInstallResult.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
+                        request.mInstallResult.mReturnCode = PackageManager.INSTALL_UNKNOWN;
+                    }
+                }
+            }
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    @GuardedBy("mInstallLock")
+    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
+            throws PrepareFailure {
+        final int installFlags = args.mInstallFlags;
+        final File tmpPackageFile = new File(args.getCodePath());
+        final boolean onExternal = args.mVolumeUuid != null;
+        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
+        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
+        final boolean virtualPreload =
+                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
+        final boolean isRollback = args.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
+        @PackageManagerService.ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
+        if (args.mMoveInfo != null) {
+            // moving a complete application; perform an initial scan on the new install location
+            scanFlags |= SCAN_INITIAL;
+        }
+        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+            scanFlags |= SCAN_DONT_KILL_APP;
+        }
+        if (instantApp) {
+            scanFlags |= SCAN_AS_INSTANT_APP;
+        }
+        if (fullApp) {
+            scanFlags |= SCAN_AS_FULL_APP;
+        }
+        if (virtualPreload) {
+            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
+        }
+
+        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
+
+        // Validity check
+        if (instantApp && onExternal) {
+            Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID);
+        }
+
+        // Retrieve PackageSettings and parse package
+        @ParsingPackageUtils.ParseFlags final int parseFlags =
+                mPm.mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
+                | ParsingPackageUtils.PARSE_ENFORCE_CODE
+                | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
+        final ParsedPackage parsedPackage;
+        try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
+            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+        } catch (PackageManagerException e) {
+            throw new PrepareFailure("Failed parse during installPackageLI", e);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+
+        // Instant apps have several additional install-time checks.
+        if (instantApp) {
+            if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+                        + " does not target at least O");
+                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+                        "Instant app package must target at least O");
+            }
+            if (parsedPackage.getSharedUserId() != null) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+                        + " may not declare sharedUserId.");
+                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+                        "Instant app package may not declare a sharedUserId");
+            }
+        }
+
+        if (parsedPackage.isStaticSharedLibrary()) {
+            // Static shared libraries have synthetic package names
+            PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
+
+            // No static shared libs on external storage
+            if (onExternal) {
+                Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                        "Packages declaring static-shared libs cannot be updated");
+            }
+        }
+
+        String pkgName = res.mName = parsedPackage.getPackageName();
+        if (parsedPackage.isTestOnly()) {
+            if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
+                throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
+            }
+        }
+
+        // either use what we've been given or parse directly from the APK
+        if (args.mSigningDetails != SigningDetails.UNKNOWN) {
+            parsedPackage.setSigningDetails(args.mSigningDetails);
+        } else {
+            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
+                    input, parsedPackage, false /*skipVerify*/);
+            if (result.isError()) {
+                throw new PrepareFailure("Failed collect during installPackageLI",
+                        result.getException());
+            }
+            parsedPackage.setSigningDetails(result.getResult());
+        }
+
+        if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
+                < SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2) {
+            Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+                    + " is not signed with at least APK Signature Scheme v2");
+            throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+                    "Instant app package must be signed with APK Signature Scheme v2 or greater");
+        }
+
+        boolean systemApp = false;
+        boolean replace = false;
+        synchronized (mPm.mLock) {
+            // Check if installing already existing package
+            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+                String oldName = mPm.mSettings.getRenamedPackageLPr(pkgName);
+                if (parsedPackage.getOriginalPackages().contains(oldName)
+                        && mPm.mPackages.containsKey(oldName)) {
+                    // This package is derived from an original package,
+                    // and this device has been updating from that original
+                    // name.  We must continue using the original name, so
+                    // rename the new package here.
+                    parsedPackage.setPackageName(oldName);
+                    pkgName = parsedPackage.getPackageName();
+                    replace = true;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Replacing existing renamed package: oldName="
+                                + oldName + " pkgName=" + pkgName);
+                    }
+                } else if (mPm.mPackages.containsKey(pkgName)) {
+                    // This package, under its official name, already exists
+                    // on the device; we should replace it.
+                    replace = true;
+                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing package: " + pkgName);
+                }
+
+                if (replace) {
+                    // Prevent apps opting out from runtime permissions
+                    AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
+                    final int oldTargetSdk = oldPackage.getTargetSdkVersion();
+                    final int newTargetSdk = parsedPackage.getTargetSdkVersion();
+                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
+                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+                        throw new PrepareFailure(
+                                PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+                                "Package " + parsedPackage.getPackageName()
+                                        + " new target SDK " + newTargetSdk
+                                        + " doesn't support runtime permissions but the old"
+                                        + " target SDK " + oldTargetSdk + " does.");
+                    }
+                    // Prevent persistent apps from being updated
+                    if (oldPackage.isPersistent()
+                            && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
+                                "Package " + oldPackage.getPackageName() + " is a persistent app. "
+                                        + "Persistent apps are not updateable.");
+                    }
+                }
+            }
+
+            PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+            if (ps != null) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
+
+                // Static shared libs have same package with different versions where
+                // we internally use a synthetic package name to allow multiple versions
+                // of the same package, therefore we need to compare signatures against
+                // the package setting for the latest library version.
+                PackageSetting signatureCheckPs = ps;
+                if (parsedPackage.isStaticSharedLibrary()) {
+                    SharedLibraryInfo libraryInfo = mPm.getLatestSharedLibraVersionLPr(
+                            parsedPackage);
+                    if (libraryInfo != null) {
+                        signatureCheckPs = mPm.mSettings.getPackageLPr(
+                                libraryInfo.getPackageName());
+                    }
+                }
+
+                // Quick validity check that we're signed correctly if updating;
+                // we'll check this again later when scanning, but we want to
+                // bail early here before tripping over redefined permissions.
+                final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+                if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
+                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+                                + parsedPackage.getPackageName() + " upgrade keys do not match the "
+                                + "previously installed version");
+                    }
+                } else {
+                    try {
+                        final boolean compareCompat = mPm.isCompatSignatureUpdateNeeded(
+                                parsedPackage);
+                        final boolean compareRecover = mPm.isRecoverSignatureUpdateNeeded(
+                                parsedPackage);
+                        // We don't care about disabledPkgSetting on install for now.
+                        final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+                                parsedPackage.getSigningDetails(), compareCompat, compareRecover,
+                                isRollback);
+                        // The new KeySets will be re-added later in the scanning process.
+                        if (compatMatch) {
+                            synchronized (mPm.mLock) {
+                                ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
+                            }
+                        }
+                    } catch (PackageManagerException e) {
+                        throw new PrepareFailure(e.error, e.getMessage());
+                    }
+                }
+
+                if (ps.pkg != null) {
+                    systemApp = ps.pkg.isSystem();
+                }
+                res.mOrigUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
+            }
+
+            final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
+            for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+                final ParsedPermissionGroup group =
+                        parsedPackage.getPermissionGroups().get(groupNum);
+                final PermissionGroupInfo sourceGroup = mPm.getPermissionGroupInfo(group.getName(),
+                        0);
+
+                if (sourceGroup != null && cannotInstallWithBadPermissionGroups(parsedPackage)) {
+                    final String sourcePackageName = sourceGroup.packageName;
+
+                    if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName))
+                            && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
+                            scanFlags)) {
+                        EventLog.writeEvent(0x534e4554, "146211400", -1,
+                                parsedPackage.getPackageName());
+
+                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP,
+                                "Package "
+                                        + parsedPackage.getPackageName()
+                                        + " attempting to redeclare permission group "
+                                        + group.getName() + " already owned by "
+                                        + sourcePackageName);
+                    }
+                }
+            }
+
+            // TODO: Move logic for checking permission compatibility into PermissionManagerService
+            final int n = ArrayUtils.size(parsedPackage.getPermissions());
+            for (int i = n - 1; i >= 0; i--) {
+                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
+                final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName());
+
+                // Don't allow anyone but the system to define ephemeral permissions.
+                if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+                        && !systemApp) {
+                    Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
+                            + " attempting to delcare ephemeral permission "
+                            + perm.getName() + "; Removing ephemeral.");
+                    perm.setProtectionLevel(
+                            perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
+                }
+
+                // Check whether the newly-scanned package wants to define an already-defined perm
+                if (bp != null) {
+                    final String sourcePackageName = bp.getPackageName();
+
+                    if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
+                            scanFlags)) {
+                        // If the owning package is the system itself, we log but allow
+                        // install to proceed; we fail the install on all other permission
+                        // redefinitions.
+                        if (!sourcePackageName.equals("android")) {
+                            throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION,
+                                    "Package "
+                                    + parsedPackage.getPackageName()
+                                    + " attempting to redeclare permission "
+                                    + perm.getName() + " already owned by "
+                                    + sourcePackageName)
+                                    .conflictsWithExistingPermission(perm.getName(),
+                                            sourcePackageName);
+                        } else {
+                            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                                    + " attempting to redeclare system permission "
+                                    + perm.getName() + "; ignoring new declaration");
+                            parsedPackage.removePermission(i);
+                        }
+                    } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
+                        // Prevent apps to change protection level to dangerous from any other
+                        // type as this would allow a privilege escalation where an app adds a
+                        // normal/signature permission in other app's group and later redefines
+                        // it as dangerous leading to the group auto-grant.
+                        if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
+                                == PermissionInfo.PROTECTION_DANGEROUS) {
+                            if (bp != null && !bp.isRuntime()) {
+                                Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                                        + " trying to change a non-runtime permission "
+                                        + perm.getName()
+                                        + " to runtime; keeping old protection level");
+                                perm.setProtectionLevel(bp.getProtectionLevel());
+                            }
+                        }
+                    }
+                }
+
+                if (perm.getGroup() != null
+                        && cannotInstallWithBadPermissionGroups(parsedPackage)) {
+                    boolean isPermGroupDefinedByPackage = false;
+                    for (int groupNum = 0; groupNum < numGroups; groupNum++) {
+                        if (parsedPackage.getPermissionGroups().get(groupNum).getName()
+                                .equals(perm.getGroup())) {
+                            isPermGroupDefinedByPackage = true;
+                            break;
+                        }
+                    }
+
+                    if (!isPermGroupDefinedByPackage) {
+                        final PermissionGroupInfo sourceGroup =
+                                mPm.getPermissionGroupInfo(perm.getGroup(), 0);
+
+                        if (sourceGroup == null) {
+                            EventLog.writeEvent(0x534e4554, "146211400", -1,
+                                    parsedPackage.getPackageName());
+
+                            throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
+                                    "Package "
+                                            + parsedPackage.getPackageName()
+                                            + " attempting to declare permission "
+                                            + perm.getName() + " in non-existing group "
+                                            + perm.getGroup());
+                        } else {
+                            String groupSourcePackageName = sourceGroup.packageName;
+
+                            if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName)
+                                    && !doesSignatureMatchForPermissions(groupSourcePackageName,
+                                    parsedPackage, scanFlags)) {
+                                EventLog.writeEvent(0x534e4554, "146211400", -1,
+                                        parsedPackage.getPackageName());
+
+                                throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
+                                        "Package "
+                                                + parsedPackage.getPackageName()
+                                                + " attempting to declare permission "
+                                                + perm.getName() + " in group "
+                                                + perm.getGroup() + " owned by package "
+                                                + groupSourcePackageName
+                                                + " with incompatible certificate");
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (systemApp) {
+            if (onExternal) {
+                // Abort update; system app can't be replaced with app on sdcard
+                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                        "Cannot install updates to system apps on sdcard");
+            } else if (instantApp) {
+                // Abort update; system app can't be replaced with an instant app
+                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
+                        "Cannot update a system app with an instant app");
+            }
+        }
+
+        if (args.mMoveInfo != null) {
+            // We did an in-place move, so dex is ready to roll
+            scanFlags |= SCAN_NO_DEX;
+            scanFlags |= SCAN_MOVE;
+
+            synchronized (mPm.mLock) {
+                final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+                if (ps == null) {
+                    res.setError(INSTALL_FAILED_INTERNAL_ERROR,
+                            "Missing settings for moved package " + pkgName);
+                }
+
+                // We moved the entire application as-is, so bring over the
+                // previously derived ABI information.
+                parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
+                        .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
+            }
+
+        } else {
+            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
+            scanFlags |= SCAN_NO_DEX;
+
+            try {
+                PackageSetting pkgSetting;
+                synchronized (mPm.mLock) {
+                    pkgSetting = mPm.mSettings.getPackageLPr(pkgName);
+                }
+                boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
+                        && pkgSetting.getPkgState().isUpdatedSystemApp();
+                final String abiOverride = deriveAbiOverride(args.mAbiOverride);
+                AndroidPackage oldPackage = mPm.mPackages.get(pkgName);
+                boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
+                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
+                        derivedAbi = mPm.mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
+                        isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
+                        abiOverride, mPm.mAppLib32InstallDir);
+                derivedAbi.first.applyTo(parsedPackage);
+                derivedAbi.second.applyTo(parsedPackage);
+            } catch (PackageManagerException pme) {
+                Slog.e(TAG, "Error deriving application ABI", pme);
+                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Error deriving application ABI: " + pme.getMessage());
+            }
+        }
+
+        if (!args.doRename(res.mReturnCode, parsedPackage)) {
+            throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
+        }
+
+        try {
+            setUpFsVerityIfPossible(parsedPackage);
+        } catch (Installer.InstallerException | IOException | DigestException
+                | NoSuchAlgorithmException e) {
+            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to set up verity: " + e);
+        }
+
+        final PackageFreezer freezer =
+                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
+        boolean shouldCloseFreezerBeforeReturn = true;
+        try {
+            final AndroidPackage existingPackage;
+            String renamedPackage = null;
+            boolean sysPkg = false;
+            int targetScanFlags = scanFlags;
+            int targetParseFlags = parseFlags;
+            final PackageSetting ps;
+            final PackageSetting disabledPs;
+            if (replace) {
+                if (parsedPackage.isStaticSharedLibrary()) {
+                    // Static libs have a synthetic package name containing the version
+                    // and cannot be updated as an update would get a new package name,
+                    // unless this is installed from adb which is useful for development.
+                    AndroidPackage existingPkg = mPm.mPackages.get(parsedPackage.getPackageName());
+                    if (existingPkg != null
+                            && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) {
+                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Packages declaring "
+                                        + "static-shared libs cannot be updated");
+                    }
+                }
+
+                final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
+
+                final AndroidPackage oldPackage;
+                final String pkgName11 = parsedPackage.getPackageName();
+                final int[] allUsers;
+                final int[] installedUsers;
+                final int[] uninstalledUsers;
+
+                synchronized (mPm.mLock) {
+                    oldPackage = mPm.mPackages.get(pkgName11);
+                    existingPackage = oldPackage;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
+                    }
+
+                    ps = mPm.mSettings.getPackageLPr(pkgName11);
+                    disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps);
+
+                    // verify signatures are valid
+                    final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+                    if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+                        if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
+                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                    "New package not signed by keys specified by upgrade-keysets: "
+                                            + pkgName11);
+                        }
+                    } else {
+                        SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
+                        SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
+                        // default to original signature matching
+                        if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
+                                SigningDetails.CertCapabilities.INSTALLED_DATA)
+                                && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
+                                SigningDetails.CertCapabilities.ROLLBACK)) {
+                            // Allow the update to proceed if this is a rollback and the parsed
+                            // package's current signing key is the current signer or in the lineage
+                            // of the old package; this allows a rollback to a previously installed
+                            // version after an app's signing key has been rotated without requiring
+                            // the rollback capability on the previous signing key.
+                            if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
+                                    parsedPkgSigningDetails)) {
+                                throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+                                        "New package has a different signature: " + pkgName11);
+                            }
+                        }
+                    }
+
+                    // don't allow a system upgrade unless the upgrade hash matches
+                    if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
+                        final byte[] digestBytes;
+                        try {
+                            final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+                            updateDigest(digest, new File(parsedPackage.getBaseApkPath()));
+                            if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
+                                for (String path : parsedPackage.getSplitCodePaths()) {
+                                    updateDigest(digest, new File(path));
+                                }
+                            }
+                            digestBytes = digest.digest();
+                        } catch (NoSuchAlgorithmException | IOException e) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "Could not compute hash: " + pkgName11);
+                        }
+                        if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
+                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
+                                    "New package fails restrict-update check: " + pkgName11);
+                        }
+                        // retain upgrade restriction
+                        parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
+                    }
+
+                    // Check for shared user id changes
+                    String invalidPackageName = null;
+                    if (!Objects.equals(oldPackage.getSharedUserId(),
+                            parsedPackage.getSharedUserId())
+                            // Don't mark as invalid if the app is trying to
+                            // leave a sharedUserId
+                            && parsedPackage.getSharedUserId() != null) {
+                        invalidPackageName = parsedPackage.getPackageName();
+                    }
+
+                    if (invalidPackageName != null) {
+                        throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+                                "Package " + invalidPackageName + " tried to change user "
+                                        + oldPackage.getSharedUserId());
+                    }
+
+                    // In case of rollback, remember per-user/profile install state
+                    allUsers = mPm.mUserManager.getUserIds();
+                    installedUsers = ps.queryInstalledUsers(allUsers, true);
+                    uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
+
+
+                    // don't allow an upgrade from full to ephemeral
+                    if (isInstantApp) {
+                        if (args.mUser == null
+                                || args.mUser.getIdentifier() == UserHandle.USER_ALL) {
+                            for (int currentUser : allUsers) {
+                                if (!ps.getInstantApp(currentUser)) {
+                                    // can't downgrade from full to instant
+                                    Slog.w(TAG,
+                                            "Can't replace full app with instant app: " + pkgName11
+                                                    + " for user: " + currentUser);
+                                    throw new PrepareFailure(
+                                            PackageManager.INSTALL_FAILED_SESSION_INVALID);
+                                }
+                            }
+                        } else if (!ps.getInstantApp(args.mUser.getIdentifier())) {
+                            // can't downgrade from full to instant
+                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
+                                    + " for user: " + args.mUser.getIdentifier());
+                            throw new PrepareFailure(
+                                    PackageManager.INSTALL_FAILED_SESSION_INVALID);
+                        }
+                    }
+                }
+
+                // Update what is removed
+                res.mRemovedInfo = new PackageRemovedInfo(mPm);
+                res.mRemovedInfo.mUid = oldPackage.getUid();
+                res.mRemovedInfo.mRemovedPackage = oldPackage.getPackageName();
+                res.mRemovedInfo.mInstallerPackageName = ps.installSource.installerPackageName;
+                res.mRemovedInfo.mIsStaticSharedLib =
+                        parsedPackage.getStaticSharedLibName() != null;
+                res.mRemovedInfo.mIsUpdate = true;
+                res.mRemovedInfo.mOrigUsers = installedUsers;
+                res.mRemovedInfo.mInstallReasons = new SparseArray<>(installedUsers.length);
+                for (int i = 0; i < installedUsers.length; i++) {
+                    final int userId = installedUsers[i];
+                    res.mRemovedInfo.mInstallReasons.put(userId, ps.getInstallReason(userId));
+                }
+                res.mRemovedInfo.mUninstallReasons = new SparseArray<>(uninstalledUsers.length);
+                for (int i = 0; i < uninstalledUsers.length; i++) {
+                    final int userId = uninstalledUsers[i];
+                    res.mRemovedInfo.mUninstallReasons.put(userId, ps.getUninstallReason(userId));
+                }
+
+                sysPkg = oldPackage.isSystem();
+                if (sysPkg) {
+                    // Set the system/privileged/oem/vendor/product flags as needed
+                    final boolean privileged = oldPackage.isPrivileged();
+                    final boolean oem = oldPackage.isOem();
+                    final boolean vendor = oldPackage.isVendor();
+                    final boolean product = oldPackage.isProduct();
+                    final boolean odm = oldPackage.isOdm();
+                    final boolean systemExt = oldPackage.isSystemExt();
+                    final @ParsingPackageUtils.ParseFlags int systemParseFlags = parseFlags;
+                    final @PackageManagerService.ScanFlags int systemScanFlags = scanFlags
+                            | SCAN_AS_SYSTEM
+                            | (privileged ? SCAN_AS_PRIVILEGED : 0)
+                            | (oem ? SCAN_AS_OEM : 0)
+                            | (vendor ? SCAN_AS_VENDOR : 0)
+                            | (product ? SCAN_AS_PRODUCT : 0)
+                            | (odm ? SCAN_AS_ODM : 0)
+                            | (systemExt ? SCAN_AS_SYSTEM_EXT : 0);
+
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
+                                + ", old=" + oldPackage);
+                    }
+                    res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+                    targetParseFlags = systemParseFlags;
+                    targetScanFlags = systemScanFlags;
+                } else { // non system replace
+                    replace = true;
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG,
+                                "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
+                                        + oldPackage);
+                    }
+                }
+            } else { // new package install
+                ps = null;
+                disabledPs = null;
+                replace = false;
+                existingPackage = null;
+                // Remember this for later, in case we need to rollback this install
+                String pkgName1 = parsedPackage.getPackageName();
+
+                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
+
+                // TODO(b/194319951): MOVE TO RECONCILE
+                synchronized (mPm.mLock) {
+                    renamedPackage = mPm.mSettings.getRenamedPackageLPr(pkgName1);
+                    if (renamedPackage != null) {
+                        // A package with the same name is already installed, though
+                        // it has been renamed to an older name.  The package we
+                        // are trying to install should be installed as an update to
+                        // the existing one, but that has not been requested, so bail.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling package running as "
+                                        + renamedPackage);
+                    }
+                    if (mPm.mPackages.containsKey(pkgName1)) {
+                        // Don't allow installation over an existing package with the same name.
+                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
+                                "Attempt to re-install " + pkgName1
+                                        + " without first uninstalling.");
+                    }
+                }
+            }
+            // we're passing the freezer back to be closed in a later phase of install
+            shouldCloseFreezerBeforeReturn = false;
+
+            return new PrepareResult(replace, targetScanFlags, targetParseFlags,
+                    existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
+                    ps, disabledPs);
+        } finally {
+            res.mFreezer = freezer;
+            if (shouldCloseFreezerBeforeReturn) {
+                freezer.close();
+            }
+        }
+    }
+
+    /*
+     * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges
+     * as this only works for packages that are installed
+     *
+     * TODO: Move logic for permission group compatibility into PermissionManagerService
+     */
+    @SuppressWarnings("AndroidFrameworkCompatChange")
+    private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) {
+        return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S;
+    }
+
+    private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
+            @NonNull ParsedPackage parsedPackage, int scanFlags) {
+        // If the defining package is signed with our cert, it's okay.  This
+        // also includes the "updating the same package" case, of course.
+        // "updating same package" could also involve key-rotation.
+
+        final PackageSetting sourcePackageSetting;
+        synchronized (mPm.mLock) {
+            sourcePackageSetting = mPm.mSettings.getPackageLPr(sourcePackageName);
+        }
+
+        final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
+                ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
+        final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+        if (sourcePackageName.equals(parsedPackage.getPackageName())
+                && (ksms.shouldCheckUpgradeKeySetLocked(
+                sourcePackageSetting, scanFlags))) {
+            return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
+        } else {
+
+            // in the event of signing certificate rotation, we need to see if the
+            // package's certificate has rotated from the current one, or if it is an
+            // older certificate with which the current is ok with sharing permissions
+            if (sourceSigningDetails.checkCapability(
+                    parsedPackage.getSigningDetails(),
+                    SigningDetails.CertCapabilities.PERMISSION)) {
+                return true;
+            } else if (parsedPackage.getSigningDetails().checkCapability(
+                    sourceSigningDetails,
+                    SigningDetails.CertCapabilities.PERMISSION)) {
+                // the scanned package checks out, has signing certificate rotation
+                // history, and is newer; bring it over
+                synchronized (mPm.mLock) {
+                    sourcePackageSetting.signatures.mSigningDetails =
+                            parsedPackage.getSigningDetails();
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Set up fs-verity for the given package if possible.  This requires a feature flag of system
+     * property to be enabled only if the kernel supports fs-verity.
+     *
+     * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
+     * kernel patches). In normal mode, all file format can be supported.
+     */
+    private void setUpFsVerityIfPossible(AndroidPackage pkg) throws Installer.InstallerException,
+            PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
+        final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+        final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+        if (!standardMode && !legacyMode) {
+            return;
+        }
+
+        if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion()
+                < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) {
+            return;
+        }
+
+        // Collect files we care for fs-verity setup.
+        ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
+        if (legacyMode) {
+            synchronized (mPm.mLock) {
+                final PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+                if (ps != null && ps.isPrivileged()) {
+                    fsverityCandidates.put(pkg.getBaseApkPath(), null);
+                    if (pkg.getSplitCodePaths() != null) {
+                        for (String splitPath : pkg.getSplitCodePaths()) {
+                            fsverityCandidates.put(splitPath, null);
+                        }
+                    }
+                }
+            }
+        } else {
+            // NB: These files will become only accessible if the signing key is loaded in kernel's
+            // .fs-verity keyring.
+            fsverityCandidates.put(pkg.getBaseApkPath(),
+                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath()));
+
+            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
+                    pkg.getBaseApkPath());
+            if (new File(dmPath).exists()) {
+                fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
+            }
+
+            if (pkg.getSplitCodePaths() != null) {
+                for (String path : pkg.getSplitCodePaths()) {
+                    fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
+
+                    final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
+                    if (new File(splitDmPath).exists()) {
+                        fsverityCandidates.put(splitDmPath,
+                                VerityUtils.getFsveritySignatureFilePath(splitDmPath));
+                    }
+                }
+            }
+        }
+
+        for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
+            final String filePath = entry.getKey();
+            final String signaturePath = entry.getValue();
+
+            if (!legacyMode) {
+                // fs-verity is optional for now.  Only set up if signature is provided.
+                if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
+                    try {
+                        VerityUtils.setUpFsverity(filePath, signaturePath);
+                    } catch (IOException e) {
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+                                "Failed to enable fs-verity: " + e);
+                    }
+                }
+                continue;
+            }
+
+            // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+            final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
+            if (result.isOk()) {
+                if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
+                final FileDescriptor fd = result.getUnownedFileDescriptor();
+                try {
+                    final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+                    try {
+                        // A file may already have fs-verity, e.g. when reused during a split
+                        // install. If the measurement succeeds, no need to attempt to set up.
+                        mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+                    } catch (Installer.InstallerException e) {
+                        mPm.mInstaller.installApkVerity(filePath, fd, result.getContentSize());
+                        mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+                    }
+                } finally {
+                    IoUtils.closeQuietly(fd);
+                }
+            } else if (result.isFailed()) {
+                throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+                        "Failed to generate verity");
+            }
+        }
+    }
+
+    private PackageFreezer freezePackageForInstall(String packageName, int installFlags,
+            String killReason) {
+        return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
+    }
+
+    private PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
+            String killReason) {
+        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+            return new PackageFreezer(mPm);
+        } else {
+            return mPm.freezePackage(packageName, userId, killReason);
+        }
+    }
+
+    private static void updateDigest(MessageDigest digest, File file) throws IOException {
+        try (DigestInputStream digestStream =
+                     new DigestInputStream(new FileInputStream(file), digest)) {
+            int length, total = 0;
+            while ((length = digestStream.read()) != -1) {
+                total += length;
+            } // just plow through the file
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void commitPackagesLocked(final CommitRequest request) {
+        // TODO: remove any expected failures from this method; this should only be able to fail due
+        //       to unavoidable errors (I/O, etc.)
+        for (ReconciledPackage reconciledPkg : request.mReconciledPackages.values()) {
+            final ScanResult scanResult = reconciledPkg.mScanResult;
+            final ScanRequest scanRequest = scanResult.mRequest;
+            final ParsedPackage parsedPackage = scanRequest.mParsedPackage;
+            final String packageName = parsedPackage.getPackageName();
+            final PackageInstalledInfo res = reconciledPkg.mInstallResult;
+
+            if (reconciledPkg.mPrepareResult.mReplace) {
+                AndroidPackage oldPackage = mPm.mPackages.get(packageName);
+
+                // Set the update and install times
+                PackageSetting deletedPkgSetting = mPm.getPackageSetting(
+                        oldPackage.getPackageName());
+                reconciledPkg.mPkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
+                reconciledPkg.mPkgSetting.lastUpdateTime = System.currentTimeMillis();
+
+                res.mRemovedInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
+                        reconciledPkg.mPkgSetting, request.mAllUsers,
+                        mPm.mSettings.getPackagesLocked());
+                if (reconciledPkg.mPrepareResult.mSystem) {
+                    // Remove existing system package
+                    mPm.removePackageLI(oldPackage, true);
+                    if (!disableSystemPackageLPw(oldPackage)) {
+                        // We didn't need to disable the .apk as a current system package,
+                        // which means we are replacing another update that is already
+                        // installed.  We need to make sure to delete the older one's .apk.
+                        res.mRemovedInfo.mArgs = mPm.createInstallArgsForExisting(
+                                oldPackage.getPath(),
+                                getAppDexInstructionSets(
+                                        AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
+                                                deletedPkgSetting),
+                                        AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
+                                                deletedPkgSetting)));
+                    } else {
+                        res.mRemovedInfo.mArgs = null;
+                    }
+                } else {
+                    try {
+                        // Settings will be written during the call to updateSettingsLI().
+                        mPm.executeDeletePackageLIF(reconciledPkg.mDeletePackageAction, packageName,
+                                true, request.mAllUsers, false);
+                    } catch (SystemDeleteException e) {
+                        if (mPm.mIsEngBuild) {
+                            throw new RuntimeException("Unexpected failure", e);
+                            // ignore; not possible for non-system app
+                        }
+                    }
+                    // Successfully deleted the old package; proceed with replace.
+
+                    // If deleted package lived in a container, give users a chance to
+                    // relinquish resources before killing.
+                    if (oldPackage.isExternalStorage()) {
+                        if (DEBUG_INSTALL) {
+                            Slog.i(TAG, "upgrading pkg " + oldPackage
+                                    + " is ASEC-hosted -> UNAVAILABLE");
+                        }
+                        final int[] uidArray = new int[]{oldPackage.getUid()};
+                        final ArrayList<String> pkgList = new ArrayList<>(1);
+                        pkgList.add(oldPackage.getPackageName());
+                        mPm.sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+                    }
+
+                    // Update the in-memory copy of the previous code paths.
+                    PackageSetting ps1 = mPm.mSettings.getPackageLPr(
+                            reconciledPkg.mPrepareResult.mExistingPackage.getPackageName());
+                    if ((reconciledPkg.mInstallArgs.mInstallFlags & PackageManager.DONT_KILL_APP)
+                            == 0) {
+                        if (ps1.mOldCodePaths == null) {
+                            ps1.mOldCodePaths = new ArraySet<>();
+                        }
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());
+                        if (oldPackage.getSplitCodePaths() != null) {
+                            Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
+                        }
+                    } else {
+                        ps1.mOldCodePaths = null;
+                    }
+
+                    if (reconciledPkg.mInstallResult.mReturnCode
+                            == PackageManager.INSTALL_SUCCEEDED) {
+                        PackageSetting ps2 = mPm.mSettings.getPackageLPr(
+                                parsedPackage.getPackageName());
+                        if (ps2 != null) {
+                            res.mRemovedInfo.mRemovedForAllUsers =
+                                    mPm.mPackages.get(ps2.name) == null;
+                        }
+                    }
+                }
+            }
+
+            AndroidPackage pkg = mPm.commitReconciledScanResultLocked(reconciledPkg,
+                    request.mAllUsers);
+            updateSettingsLI(pkg, reconciledPkg.mInstallArgs, request.mAllUsers, res);
+
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+            if (ps != null) {
+                res.mNewUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
+                ps.setUpdateAvailable(false /*updateAvailable*/);
+            }
+            if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
+                mPm.updateSequenceNumberLP(ps, res.mNewUsers);
+                mPm.updateInstantAppInstallerLocked(packageName);
+            }
+        }
+        ApplicationPackageManager.invalidateGetPackagesForUidCache();
+    }
+
+    @GuardedBy("mLock")
+    private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
+        return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
+    }
+
+    private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
+            int[] allUsers, PackageInstalledInfo res) {
+        updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
+    }
+
+    private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
+            int[] allUsers, PackageInstalledInfo res) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
+
+        final String pkgName = pkg.getPackageName();
+        final int[] installedForUsers = res.mOrigUsers;
+        final int installReason = installArgs.mInstallReason;
+        InstallSource installSource = installArgs.mInstallSource;
+        final String installerPackageName = installSource.installerPackageName;
+
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
+        synchronized (mPm.mLock) {
+            // For system-bundled packages, we assume that installing an upgraded version
+            // of the package implies that the user actually wants to run that new code,
+            // so we enable the package.
+            final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName);
+            final int userId = installArgs.mUser.getIdentifier();
+            if (ps != null) {
+                if (pkg.isSystem()) {
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
+                    }
+                    // Enable system package for requested users
+                    if (res.mOrigUsers != null) {
+                        for (int origUserId : res.mOrigUsers) {
+                            if (userId == UserHandle.USER_ALL || userId == origUserId) {
+                                ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
+                                        origUserId, installerPackageName);
+                            }
+                        }
+                    }
+                    // Also convey the prior install/uninstall state
+                    if (allUsers != null && installedForUsers != null) {
+                        for (int currentUserId : allUsers) {
+                            final boolean installed = ArrayUtils.contains(
+                                    installedForUsers, currentUserId);
+                            if (DEBUG_INSTALL) {
+                                Slog.d(TAG, "    user " + currentUserId + " => " + installed);
+                            }
+                            ps.setInstalled(installed, currentUserId);
+                        }
+                        // these install state changes will be persisted in the
+                        // upcoming call to mSettings.writeLPr().
+                    }
+
+                    if (allUsers != null) {
+                        for (int currentUserId : allUsers) {
+                            ps.resetOverrideComponentLabelIcon(currentUserId);
+                        }
+                    }
+                }
+
+                // Retrieve the overlays for shared libraries of the package.
+                if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
+                    for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
+                        for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
+                            if (!sharedLib.isDynamic()) {
+                                // TODO(146804378): Support overlaying static shared libraries
+                                continue;
+                            }
+                            final PackageSetting libPs = mPm.mSettings.getPackageLPr(
+                                    sharedLib.getPackageName());
+                            if (libPs == null) {
+                                continue;
+                            }
+                            ps.setOverlayPathsForLibrary(sharedLib.getName(),
+                                    libPs.getOverlayPaths(currentUserId), currentUserId);
+                        }
+                    }
+                }
+
+                // It's implied that when a user requests installation, they want the app to be
+                // installed and enabled. (This does not apply to USER_ALL, which here means only
+                // install on users for which the app is already installed).
+                if (userId != UserHandle.USER_ALL) {
+                    ps.setInstalled(true, userId);
+                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+                }
+
+                mPm.mSettings.addInstallerPackageNames(ps.installSource);
+
+                // When replacing an existing package, preserve the original install reason for all
+                // users that had the package installed before. Similarly for uninstall reasons.
+                final Set<Integer> previousUserIds = new ArraySet<>();
+                if (res.mRemovedInfo != null && res.mRemovedInfo.mInstallReasons != null) {
+                    final int installReasonCount = res.mRemovedInfo.mInstallReasons.size();
+                    for (int i = 0; i < installReasonCount; i++) {
+                        final int previousUserId = res.mRemovedInfo.mInstallReasons.keyAt(i);
+                        final int previousInstallReason =
+                                res.mRemovedInfo.mInstallReasons.valueAt(i);
+                        ps.setInstallReason(previousInstallReason, previousUserId);
+                        previousUserIds.add(previousUserId);
+                    }
+                }
+                if (res.mRemovedInfo != null && res.mRemovedInfo.mUninstallReasons != null) {
+                    for (int i = 0; i < res.mRemovedInfo.mUninstallReasons.size(); i++) {
+                        final int previousUserId = res.mRemovedInfo.mUninstallReasons.keyAt(i);
+                        final int previousReason = res.mRemovedInfo.mUninstallReasons.valueAt(i);
+                        ps.setUninstallReason(previousReason, previousUserId);
+                    }
+                }
+
+                // Set install reason for users that are having the package newly installed.
+                final int[] allUsersList = mPm.mUserManager.getUserIds();
+                if (userId == UserHandle.USER_ALL) {
+                    // TODO(b/152629990): It appears that the package doesn't actually get newly
+                    //  installed in this case, so the installReason shouldn't get modified?
+                    for (int currentUserId : allUsersList) {
+                        if (!previousUserIds.contains(currentUserId)) {
+                            ps.setInstallReason(installReason, currentUserId);
+                        }
+                    }
+                } else if (!previousUserIds.contains(userId)) {
+                    ps.setInstallReason(installReason, userId);
+                }
+
+                // TODO(b/169721400): generalize Incremental States and create a Callback object
+                // that can be used for all the packages.
+                final String codePath = ps.getPathString();
+                if (IncrementalManager.isIncrementalPath(codePath)
+                        && mPm.mIncrementalManager != null) {
+                    final IncrementalStatesCallback incrementalStatesCallback =
+                            new IncrementalStatesCallback(ps.name, mPm);
+                    ps.setIncrementalStatesCallback(incrementalStatesCallback);
+                    mPm.mIncrementalManager.registerLoadingProgressCallback(codePath,
+                            new IncrementalProgressListener(ps.name, mPm));
+                }
+
+                // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
+                for (int currentUserId : allUsersList) {
+                    if (ps.getInstalled(currentUserId)) {
+                        ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
+                    }
+                }
+
+                mPm.mSettings.writeKernelMappingLPr(ps);
+
+                final PermissionManagerServiceInternal.PackageInstalledParams.Builder
+                        permissionParamsBuilder =
+                        new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
+                final boolean grantPermissions = (installArgs.mInstallFlags
+                        & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+                if (grantPermissions) {
+                    final List<String> grantedPermissions =
+                            installArgs.mInstallGrantPermissions != null
+                                    ? Arrays.asList(installArgs.mInstallGrantPermissions)
+                                    : pkg.getRequestedPermissions();
+                    permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
+                }
+                final boolean allowlistAllRestrictedPermissions =
+                        (installArgs.mInstallFlags
+                                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
+                final List<String> allowlistedRestrictedPermissions =
+                        allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
+                                : installArgs.mAllowlistedRestrictedPermissions;
+                if (allowlistedRestrictedPermissions != null) {
+                    permissionParamsBuilder.setAllowlistedRestrictedPermissions(
+                            allowlistedRestrictedPermissions);
+                }
+                final int autoRevokePermissionsMode = installArgs.mAutoRevokePermissionsMode;
+                permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
+                mPm.mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(),
+                        userId);
+            }
+            res.mName = pkgName;
+            res.mUid = pkg.getUid();
+            res.mPkg = pkg;
+            res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
+            //to update install status
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
+            mPm.writeSettingsLPrTEMP();
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+
+        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+    }
+
+    /**
+     * On successful install, executes remaining steps after commit completes and the package lock
+     * is released. These are typically more expensive or require calls to installd, which often
+     * locks on {@link com.android.server.pm.PackageManagerService.mLock}.
+     */
+    private void executePostCommitSteps(CommitRequest commitRequest) {
+        final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
+        for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) {
+            final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags
+                    & SCAN_AS_INSTANT_APP) != 0);
+            final AndroidPackage pkg = reconciledPkg.mPkgSetting.pkg;
+            final String packageName = pkg.getPackageName();
+            final String codePath = pkg.getPath();
+            final boolean onIncremental = mPm.mIncrementalManager != null
+                    && isIncrementalPath(codePath);
+            if (onIncremental) {
+                IncrementalStorage storage = mPm.mIncrementalManager.openStorage(codePath);
+                if (storage == null) {
+                    throw new IllegalArgumentException(
+                            "Install: null storage for incremental package " + packageName);
+                }
+                incrementalStorages.add(storage);
+            }
+            mPm.prepareAppDataAfterInstallLIF(pkg);
+            if (reconciledPkg.mPrepareResult.mClearCodeCache) {
+                mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
+                        | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            }
+            if (reconciledPkg.mPrepareResult.mReplace) {
+                mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(),
+                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
+            }
+
+            // Prepare the application profiles for the new code paths.
+            // This needs to be done before invoking dexopt so that any install-time profile
+            // can be used for optimizations.
+            mPm.mArtManagerService.prepareAppProfiles(
+                    pkg,
+                    mPm.resolveUserIds(reconciledPkg.mInstallArgs.mUser.getIdentifier()),
+                    /* updateReferenceProfileContent= */ true);
+
+            // Compute the compilation reason from the installation scenario.
+            final int compilationReason =
+                    mPm.getDexManager().getCompilationReasonForInstallScenario(
+                            reconciledPkg.mInstallArgs.mInstallScenario);
+
+            // Construct the DexoptOptions early to see if we should skip running dexopt.
+            //
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` may not be in `mPackages` yet.
+            //
+            // Also, don't fail application installs if the dexopt step fails.
+            final boolean isBackupOrRestore =
+                    reconciledPkg.mInstallArgs.mInstallReason == INSTALL_REASON_DEVICE_RESTORE
+                            || reconciledPkg.mInstallArgs.mInstallReason
+                            == INSTALL_REASON_DEVICE_SETUP;
+
+            final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
+                    | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
+                    | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);
+            DexoptOptions dexoptOptions =
+                    new DexoptOptions(packageName, compilationReason, dexoptFlags);
+
+            // Check whether we need to dexopt the app.
+            //
+            // NOTE: it is IMPORTANT to call dexopt:
+            //   - after doRename which will sync the package data from AndroidPackage and
+            //     its corresponding ApplicationInfo.
+            //   - after installNewPackageLIF or replacePackageLIF which will update result with the
+            //     uid of the application (pkg.applicationInfo.uid).
+            //     This update happens in place!
+            //
+            // We only need to dexopt if the package meets ALL of the following conditions:
+            //   1) it is not an instant app or if it is then dexopt is enabled via gservices.
+            //   2) it is not debuggable.
+            //   3) it is not on Incremental File System.
+            //
+            // Note that we do not dexopt instant apps by default. dexopt can take some time to
+            // complete, so we skip this step during installation. Instead, we'll take extra time
+            // the first time the instant app starts. It's preferred to do it this way to provide
+            // continuous progress to the useur instead of mysteriously blocking somewhere in the
+            // middle of running an instant app. The default behaviour can be overridden
+            // via gservices.
+            //
+            // Furthermore, dexopt may be skipped, depending on the install scenario and current
+            // state of the device.
+            //
+            // TODO(b/174695087): instantApp and onIncremental should be removed and their install
+            //       path moved to SCENARIO_FAST.
+            final boolean performDexopt =
+                    (!instantApp || android.provider.Settings.Global.getInt(
+                            mPm.mContext.getContentResolver(),
+                            android.provider.Settings.Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
+                            && !pkg.isDebuggable()
+                            && (!onIncremental)
+                            && dexoptOptions.isCompilationEnabled();
+
+            if (performDexopt) {
+                // Compile the layout resources.
+                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
+                    mPm.mViewCompiler.compileLayouts(pkg);
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+                ScanResult result = reconciledPkg.mScanResult;
+
+                // This mirrors logic from commitReconciledScanResultLocked, where the library files
+                // needed for dexopt are assigned.
+                // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
+                //  setting needs to be passed to have a comparison, hide it behind an immutable
+                //  interface. There's no good reason to have 3 different ways to access the real
+                //  PackageSetting object, only one of which is actually correct.
+                PackageSetting realPkgSetting = result.mExistingSettingCopied
+                        ? result.mRequest.mPkgSetting : result.mPkgSetting;
+                if (realPkgSetting == null) {
+                    realPkgSetting = reconciledPkg.mPkgSetting;
+                }
+
+                // Unfortunately, the updated system app flag is only tracked on this PackageSetting
+                boolean isUpdatedSystemApp = reconciledPkg.mPkgSetting.getPkgState()
+                        .isUpdatedSystemApp();
+
+                realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
+
+                mPm.mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
+                        null /* instructionSets */,
+                        mPm.getOrCreateCompilerPackageStats(pkg),
+                        mPm.getDexManager().getPackageUseInfoOrDefault(packageName),
+                        dexoptOptions);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
+
+            // Notify BackgroundDexOptService that the package has been changed.
+            // If this is an update of a package which used to fail to compile,
+            // BackgroundDexOptService will remove it from its denylist.
+            // TODO: Layering violation
+            BackgroundDexOptService.notifyPackageChanged(packageName);
+
+            notifyPackageChangeObserversOnUpdate(reconciledPkg);
+        }
+        waitForNativeBinariesExtraction(incrementalStorages);
+    }
+
+    private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
+        final PackageSetting pkgSetting = reconciledPkg.mPkgSetting;
+        final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.mInstallResult;
+        final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.mRemovedInfo;
+
+        PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+        pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName();
+        pkgChangeEvent.version = pkgSetting.versionCode;
+        pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime;
+        pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.mIsUpdate);
+        pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.mDataRemoved);
+        pkgChangeEvent.isDeleted = false;
+
+        mPm.notifyPackageChangeObservers(pkgChangeEvent);
+    }
+
+    static void waitForNativeBinariesExtraction(
+            ArraySet<IncrementalStorage> incrementalStorages) {
+        if (incrementalStorages.isEmpty()) {
+            return;
+        }
+        try {
+            // Native library extraction may take very long time: each page could potentially
+            // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds
+            // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't
+            // make much sense as blocking here doesn't lock up the framework, but only blocks
+            // the installation session and the following ones.
+            Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract");
+            for (int i = 0; i < incrementalStorages.size(); ++i) {
+                IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i);
+                storage.waitForNativeBinariesExtraction();
+            }
+        } finally {
+            Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract");
+        }
+    }
+
+    /**
+     * Ensure that the install reason matches what we know about the package installer (e.g. whether
+     * it is acting on behalf on an enterprise or the user).
+     *
+     * Note that the ordering of the conditionals in this method is important. The checks we perform
+     * are as follows, in this order:
+     *
+     * 1) If the install is being performed by a system app, we can trust the app to have set the
+     *    install reason correctly. Thus, we pass through the install reason unchanged, no matter
+     *    what it is.
+     * 2) If the install is being performed by a device or profile owner app, the install reason
+     *    should be enterprise policy. However, we cannot be sure that the device or profile owner
+     *    set the install reason correctly. If the app targets an older SDK version where install
+     *    reasons did not exist yet, or if the app author simply forgot, the install reason may be
+     *    unset or wrong. Thus, we force the install reason to be enterprise policy.
+     * 3) In all other cases, the install is being performed by a regular app that is neither part
+     *    of the system nor a device or profile owner. We have no reason to believe that this app is
+     *    acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+     *    set to enterprise policy and if so, change it to unknown instead.
+     */
+    private int fixUpInstallReason(String installerPackageName, int installerUid,
+            int installReason) {
+        if (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+                == PERMISSION_GRANTED) {
+            // If the install is being performed by a system app, we trust that app to have set the
+            // install reason correctly.
+            return installReason;
+        }
+        final String ownerPackage = mPm.mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(
+                UserHandle.getUserId(installerUid));
+        if (ownerPackage != null && ownerPackage.equals(installerPackageName)) {
+            // If the install is being performed by a device or profile owner, the install
+            // reason should be enterprise policy.
+            return PackageManager.INSTALL_REASON_POLICY;
+        }
+
+
+        if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+            // If the install is being performed by a regular app (i.e. neither system app nor
+            // device or profile owner), we have no reason to believe that the app is acting on
+            // behalf of an enterprise. If the app set the install reason to enterprise policy,
+            // change it to unknown instead.
+            return PackageManager.INSTALL_REASON_UNKNOWN;
+        }
+
+        // If the install is being performed by a regular app and the install reason was set to any
+        // value but enterprise policy, leave the install reason unchanged.
+        return installReason;
+    }
+
+    public void installStage() {
+        final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+        setTraceMethod("installStage").setTraceCookie(System.identityHashCode(this));
+        msg.obj = this;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+
+        mPm.mHandler.sendMessage(msg);
+    }
+
+    public void installStage(List<InstallParams> children)
+            throws PackageManagerException {
+        final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+        final MultiPackageInstallParams params =
+                new MultiPackageInstallParams(this, children);
+        params.setTraceMethod("installStageMultiPackage")
+                .setTraceCookie(System.identityHashCode(params));
+        msg.obj = params;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+        mPm.mHandler.sendMessage(msg);
+    }
+
+    public void movePackage() {
+        final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
+        setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(this));
+        msg.obj = this;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+        mPm.mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Container for a multi-package install which refers to all install sessions and args being
+     * committed together.
+     */
+    final class MultiPackageInstallParams extends HandlerParams {
+        private final List<InstallParams> mChildParams;
+        private final Map<InstallArgs, Integer> mCurrentState;
+
+        MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
+                throws PackageManagerException {
+            super(parent.getUser());
+            if (childParams.size() == 0) {
+                throw new PackageManagerException("No child sessions found!");
+            }
+            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());
+        }
+
+        @Override
+        void handleStartCopy() {
+            for (InstallParams params : mChildParams) {
+                params.handleStartCopy();
+            }
+        }
+
+        @Override
+        void handleReturnCode() {
+            for (InstallParams params : mChildParams) {
+                params.handleReturnCode();
+            }
+        }
+
+        void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
+            mCurrentState.put(args, currentStatus);
+            if (mCurrentState.size() != mChildParams.size()) {
+                return;
+            }
+            int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+            for (Integer status : mCurrentState.values()) {
+                if (status == PackageManager.INSTALL_UNKNOWN) {
+                    return;
+                } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+                    completeStatus = status;
+                    break;
+                }
+            }
+            final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
+            for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
+                installRequests.add(new InstallRequest(entry.getKey(),
+                        new PackageInstalledInfo(completeStatus)));
+            }
+            processInstallRequestsAsync(
+                    completeStatus == PackageManager.INSTALL_SUCCEEDED,
+                    installRequests);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/services/core/java/com/android/server/pm/InstallRequest.java
similarity index 68%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to services/core/java/com/android/server/pm/InstallRequest.java
index c7c2ad8..753d012 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -14,6 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.pm;
 
-parcelable InputConnectionCommand;
+final class InstallRequest {
+    public final InstallArgs mArgs;
+    public final PackageInstalledInfo mInstallResult;
+
+    InstallRequest(InstallArgs args, PackageInstalledInfo res) {
+        mArgs = args;
+        mInstallResult = res;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index fe74889..1b919f9 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -17,10 +17,10 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 
 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
 
-import android.content.pm.PackageParser;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Base64;
@@ -801,7 +801,7 @@
         long identifier = parser.getAttributeLong(null, "identifier");
         int refCount = 0;
         byte[] publicKey = parser.getAttributeBytesBase64(null, "value", null);
-        PublicKey pub = PackageParser.parsePublicKey(publicKey);
+        PublicKey pub = parsePublicKey(publicKey);
         if (pub != null) {
             PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
             mPublicKeys.put(identifier, pkh);
diff --git a/services/core/java/com/android/server/pm/MoveInfo.java b/services/core/java/com/android/server/pm/MoveInfo.java
new file mode 100644
index 0000000..5ab86d6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MoveInfo.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+final class MoveInfo {
+    final int mMoveId;
+    final String mFromUuid;
+    final String mToUuid;
+    final String mPackageName;
+    final int mAppId;
+    final String mSeInfo;
+    final int mTargetSdkVersion;
+    final String mFromCodePath;
+
+    MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
+            int appId, String seInfo, int targetSdkVersion,
+            String fromCodePath) {
+        mMoveId = moveId;
+        mFromUuid = fromUuid;
+        mToUuid = toUuid;
+        mPackageName = packageName;
+        mAppId = appId;
+        mSeInfo = seInfo;
+        mTargetSdkVersion = targetSdkVersion;
+        mFromCodePath = fromCodePath;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/MoveInstallArgs.java b/services/core/java/com/android/server/pm/MoveInstallArgs.java
new file mode 100644
index 0000000..35827a1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MoveInstallArgs.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
+import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
+
+import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.io.File;
+
+/**
+ * Logic to handle movement of existing installed applications.
+ */
+final class MoveInstallArgs extends InstallArgs {
+    private File mCodeFile;
+
+    /** New install */
+    MoveInstallArgs(InstallParams params) {
+        super(params);
+    }
+
+    int copyApk() {
+        if (DEBUG_INSTALL) {
+            Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from "
+                    + mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid);
+        }
+        synchronized (mPm.mInstaller) {
+            try {
+                mPm.mInstaller.moveCompleteApp(mMoveInfo.mFromUuid, mMoveInfo.mToUuid,
+                        mMoveInfo.mPackageName, mMoveInfo.mAppId, mMoveInfo.mSeInfo,
+                        mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath);
+            } catch (Installer.InstallerException e) {
+                Slog.w(TAG, "Failed to move app", e);
+                return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            }
+        }
+
+        final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
+        mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName);
+        if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + mCodeFile);
+
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+
+    int doPreInstall(int status) {
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp(mMoveInfo.mToUuid);
+        }
+        return status;
+    }
+
+    @Override
+    boolean doRename(int status, ParsedPackage parsedPackage) {
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp(mMoveInfo.mToUuid);
+            return false;
+        }
+
+        return true;
+    }
+
+    int doPostInstall(int status, int uid) {
+        if (status == PackageManager.INSTALL_SUCCEEDED) {
+            cleanUp(mMoveInfo.mFromUuid);
+        } else {
+            cleanUp(mMoveInfo.mToUuid);
+        }
+        return status;
+    }
+
+    @Override
+    String getCodePath() {
+        return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
+    }
+
+    private void cleanUp(String volumeUuid) {
+        final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
+        final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
+                toPathName);
+        Slog.d(TAG, "Cleaning up " + mMoveInfo.mPackageName + " on " + volumeUuid);
+        final int[] userIds = mPm.mUserManager.getUserIds();
+        synchronized (mPm.mInstallLock) {
+            // Clean up both app data and code
+            // All package moves are frozen until finished
+
+            // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
+            // this task was only focused on moving data on internal storage.
+            // We don't want ART profiles cleared, because they don't move,
+            // so we would be deleting the only copy (b/149200535).
+            final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
+                    | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
+            for (int userId : userIds) {
+                try {
+                    mPm.mInstaller.destroyAppData(volumeUuid, mMoveInfo.mPackageName, userId, flags,
+                            0);
+                } catch (Installer.InstallerException e) {
+                    Slog.w(TAG, String.valueOf(e));
+                }
+            }
+            mPm.removeCodePathLI(codeFile);
+        }
+    }
+
+    void cleanUpResourcesLI() {
+        throw new UnsupportedOperationException();
+    }
+
+    boolean doPostDeleteLI(boolean delete) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/services/core/java/com/android/server/pm/OriginInfo.java b/services/core/java/com/android/server/pm/OriginInfo.java
new file mode 100644
index 0000000..b2fbd32
--- /dev/null
+++ b/services/core/java/com/android/server/pm/OriginInfo.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import java.io.File;
+
+final class OriginInfo {
+    /**
+     * Location where install is coming from, before it has been
+     * copied/renamed into place. This could be a single monolithic APK
+     * file, or a cluster directory. This location may be untrusted.
+     */
+    final File mFile;
+
+    /**
+     * Flag indicating that {@link #mFile} has already been staged, meaning downstream users
+     * don't need to defensively copy the contents.
+     */
+    final boolean mStaged;
+
+    /**
+     * Flag indicating that {@link #mFile} is an already installed app that is being moved.
+     */
+    final boolean mExisting;
+
+    final String mResolvedPath;
+    final File mResolvedFile;
+
+    static OriginInfo fromNothing() {
+        return new OriginInfo(null, false, false);
+    }
+
+    static OriginInfo fromExistingFile(File file) {
+        return new OriginInfo(file, false, true);
+    }
+
+    static OriginInfo fromStagedFile(File file) {
+        return new OriginInfo(file, true, false);
+    }
+
+    private OriginInfo(File file, boolean staged, boolean existing) {
+        mFile = file;
+        mStaged = staged;
+        mExisting = existing;
+
+        if (file != null) {
+            mResolvedPath = file.getAbsolutePath();
+            mResolvedFile = file;
+        } else {
+            mResolvedPath = null;
+            mResolvedFile = null;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 44f7d88..dd22fd6 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -210,7 +210,7 @@
         if (paths.size() != classLoaderContexts.length) {
             String[] splitCodePaths = pkg.getSplitCodePaths();
             throw new IllegalStateException("Inconsistent information "
-                + "between PackageParser.Package and its ApplicationInfo. "
+                + "between AndroidPackage and its ApplicationInfo. "
                 + "pkg.getAllCodePaths=" + paths
                 + " pkg.getBaseCodePath=" + pkg.getBaseApkPath()
                 + " pkg.getSplitCodePaths="
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
new file mode 100644
index 0000000..395f3b4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+
+import dalvik.system.CloseGuard;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class that freezes and kills the given package upon creation, and
+ * unfreezes it upon closing. This is typically used when doing surgery on
+ * app code/data to prevent the app from running while you're working.
+ */
+final class PackageFreezer implements AutoCloseable {
+    private final String mPackageName;
+
+    private final boolean mWeFroze;
+
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    @NonNull
+    private final PackageManagerService mPm;
+
+    /**
+     * Create and return a stub freezer that doesn't actually do anything,
+     * typically used when someone requested
+     * {@link PackageManager#INSTALL_DONT_KILL_APP} or
+     * {@link PackageManager#DELETE_DONT_KILL_APP}.
+     */
+    PackageFreezer(PackageManagerService pm) {
+        mPm = pm;
+        mPackageName = null;
+        mWeFroze = false;
+        mCloseGuard.open("close");
+    }
+
+    PackageFreezer(String packageName, int userId, String killReason,
+            PackageManagerService pm) {
+        mPm = pm;
+        mPackageName = packageName;
+        final PackageSetting ps;
+        synchronized (mPm.mLock) {
+            mWeFroze = mPm.mFrozenPackages.add(mPackageName);
+            ps = mPm.mSettings.getPackageLPr(mPackageName);
+        }
+        if (ps != null) {
+            mPm.killApplication(ps.name, ps.appId, userId, killReason);
+        }
+        mCloseGuard.open("close");
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public void close() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            synchronized (mPm.mLock) {
+                if (mWeFroze) {
+                    mPm.mFrozenPackages.remove(mPackageName);
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
new file mode 100644
index 0000000..afe6bb2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.content.pm.PackageParser;
+import android.util.ExceptionUtils;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.util.ArrayList;
+
+final class PackageInstalledInfo {
+    String mName;
+    int mUid;
+    // The set of users that originally had this package installed.
+    int[] mOrigUsers;
+    // The set of users that now have this package installed.
+    int[] mNewUsers;
+    AndroidPackage mPkg;
+    int mReturnCode;
+    String mReturnMsg;
+    String mInstallerPackageName;
+    PackageRemovedInfo mRemovedInfo;
+    // The set of packages consuming this shared library or null if no consumers exist.
+    ArrayList<AndroidPackage> mLibraryConsumers;
+    PackageFreezer mFreezer;
+
+    // In some error cases we want to convey more info back to the observer
+    String mOrigPackage;
+    String mOrigPermission;
+
+    PackageInstalledInfo(int currentStatus) {
+        mReturnCode = currentStatus;
+        mUid = -1;
+        mPkg = null;
+        mRemovedInfo = null;
+    }
+
+    public void setError(int code, String msg) {
+        setReturnCode(code);
+        setReturnMessage(msg);
+        Slog.w(TAG, msg);
+    }
+
+    public void setError(String msg, PackageParser.PackageParserException e) {
+        setReturnCode(e.error);
+        setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
+        Slog.w(TAG, msg, e);
+    }
+
+    public void setError(String msg, PackageManagerException e) {
+        mReturnCode = e.error;
+        setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
+        Slog.w(TAG, msg, e);
+    }
+
+    public void setReturnCode(int returnCode) {
+        mReturnCode = returnCode;
+    }
+
+    private void setReturnMessage(String returnMsg) {
+        mReturnMsg = returnMsg;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ed6823f..3d63dcf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2384,8 +2384,7 @@
 
     private void verifyNonStaged()
             throws PackageManagerException {
-        final PackageManagerService.VerificationParams verifyingSession =
-                prepareForVerification();
+        final VerificationParams verifyingSession = prepareForVerification();
         if (isMultiPackage()) {
             final List<PackageInstallerSession> childSessions = getChildSessions();
             // Spot check to reject a non-staged multi package install of APEXes and APKs.
@@ -2395,14 +2394,14 @@
                     PackageManager.INSTALL_FAILED_SESSION_INVALID,
                     "Non-staged multi package install of APEX and APK packages is not supported");
             }
-            List<PackageManagerService.VerificationParams> verifyingChildSessions =
+            List<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.VerificationParams verifyingChildSession =
+                    final VerificationParams verifyingChildSession =
                             session.prepareForVerification();
                     verifyingChildSessions.add(verifyingChildSession);
                 } catch (PackageManagerException e) {
@@ -2416,9 +2415,9 @@
                         failure.error, failure.getLocalizedMessage(), null);
                 return;
             }
-            mPm.verifyStage(verifyingSession, verifyingChildSessions);
+            verifyingSession.verifyStage(verifyingChildSessions);
         } else {
-            mPm.verifyStage(verifyingSession);
+            verifyingSession.verifyStage();
         }
     }
 
@@ -2433,21 +2432,20 @@
 
     private void installNonStaged()
             throws PackageManagerException {
-        final PackageManagerService.InstallParams installingSession = makeInstallParams();
+        final InstallParams installingSession = makeInstallParams();
         if (installingSession == null) {
             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                     "Session should contain at least one apk session for installation");
         }
         if (isMultiPackage()) {
             final List<PackageInstallerSession> childSessions = getChildSessions();
-            List<PackageManagerService.InstallParams> installingChildSessions =
-                    new ArrayList<>(childSessions.size());
+            List<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.InstallParams installingChildSession =
+                    final InstallParams installingChildSession =
                             session.makeInstallParams();
                     if (installingChildSession != null) {
                         installingChildSessions.add(installingChildSession);
@@ -2463,20 +2461,19 @@
                         failure.error, failure.getLocalizedMessage(), null);
                 return;
             }
-            mPm.installStage(installingSession, installingChildSessions);
+            installingSession.installStage(installingChildSessions);
         } else {
-            mPm.installStage(installingSession);
+            installingSession.installStage();
         }
     }
 
     /**
      * Stages this session for verification and returns a
-     * {@link PackageManagerService.VerificationParams} representing this new staged state or null
+     * {@link VerificationParams} representing this new staged state or null
      * in case permissions need to be requested before verification can proceed.
      */
     @NonNull
-    private PackageManagerService.VerificationParams prepareForVerification()
-            throws PackageManagerException {
+    private VerificationParams prepareForVerification() throws PackageManagerException {
         assertNotLocked("makeSessionActive");
 
         synchronized (mLock) {
@@ -2603,9 +2600,9 @@
     @GuardedBy("mLock")
     @Nullable
     /**
-     * Returns a {@link com.android.server.pm.PackageManagerService.VerificationParams}
+     * Returns a {@link com.android.server.pm.VerificationParams}
      */
-    private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
+    private VerificationParams makeVerificationParamsLocked() {
         final IPackageInstallObserver2 localObserver;
         if (!hasParentSessionId()) {
             // Avoid attaching this observer to child session since they won't use it.
@@ -2618,11 +2615,13 @@
                 @Override
                 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                         Bundle extras) {
-                    if (returnCode == INSTALL_SUCCEEDED) {
-                        onVerificationComplete();
-                    } else {
-                        onSessionVerificationFailure(returnCode, msg);
-                    }
+                    mHandler.post(() -> {
+                        if (returnCode == INSTALL_SUCCEEDED) {
+                            onVerificationComplete();
+                        } else {
+                            onSessionVerificationFailure(returnCode, msg);
+                        }
+                    });
                 }
             };
         } else {
@@ -2638,10 +2637,11 @@
 
         mRelinquished = true;
 
-        return mPm.new VerificationParams(user, stageDir, localObserver, params,
-                mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
+        return new VerificationParams(user, stageDir, localObserver, params,
+                mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite, mPm);
     }
 
+    @WorkerThread
     private void onVerificationComplete() {
         // APK verification is done. Continue the installation depending on whether it is a
         // staged session or not. For a staged session, we will hand it over to the staging
@@ -2656,10 +2656,10 @@
 
     /**
      * Stages this session for install and returns a
-     * {@link PackageManagerService.InstallParams} representing this new staged state.
+     * {@link InstallParams} representing this new staged state.
      */
     @Nullable
-    private PackageManagerService.InstallParams makeInstallParams()
+    private InstallParams makeInstallParams()
             throws PackageManagerException {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2722,8 +2722,8 @@
         }
 
         synchronized (mLock) {
-            return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
-                    mSigningDetails, mInstallerUid, mPackageLite);
+            return new InstallParams(stageDir, localObserver, params, mInstallSource, user,
+                    mSigningDetails, mInstallerUid, mPackageLite, mPm);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4d0a5a3..d2c15ab 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,14 +21,10 @@
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_DEFAULT;
 import static android.content.Intent.CATEGORY_HOME;
-import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
-import static android.content.Intent.EXTRA_PACKAGE_NAME;
-import static android.content.Intent.EXTRA_VERSION_CODE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -36,36 +32,17 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
-import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
-import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID;
-import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
 import static android.content.pm.PackageManager.INSTALL_INTERNAL;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
-import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
-import static android.content.pm.PackageManager.INSTALL_STAGED;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.MATCH_ALL;
@@ -95,11 +72,9 @@
 import static android.content.pm.PackageManager.TYPE_UNKNOWN;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
 import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
-import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
 import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
 import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED;
-import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.incremental.IncrementalManager.isIncrementalPath;
@@ -118,7 +93,6 @@
 import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
-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;
@@ -211,7 +185,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageManagerInternal.PrivateResolveFlags;
-import android.content.pm.PackageParser;
 import android.content.pm.PackagePartitions;
 import android.content.pm.PackagePartitions.SystemPartition;
 import android.content.pm.PackageStats;
@@ -233,10 +206,8 @@
 import android.content.pm.TestUtilityService;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.VerifierInfo;
 import android.content.pm.VersionedPackage;
 import android.content.pm.dex.ArtManager;
-import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
 import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.ApkLiteParseUtils;
@@ -247,8 +218,6 @@
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.parsing.component.ParsedProcess;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
@@ -279,7 +248,6 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.SystemClock;
@@ -288,7 +256,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.incremental.IncrementalManager;
-import android.os.incremental.IncrementalStorage;
 import android.os.incremental.PerUidReadTimeouts;
 import android.os.storage.DiskInfo;
 import android.os.storage.IStorageManager;
@@ -303,11 +270,9 @@
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
-import android.security.SystemKeyStore;
 import android.service.pm.PackageServiceDumpProto;
 import android.stats.storage.StorageEnums;
 import android.system.ErrnoException;
-import android.system.Os;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -324,6 +289,7 @@
 import android.util.PackageUtils;
 import android.util.Pair;
 import android.util.PrintStreamPrinter;
+import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -362,6 +328,7 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
+import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.PackageWatchdog;
@@ -393,7 +360,6 @@
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 import com.android.server.pm.permission.LegacyPermissionManagerService;
-import com.android.server.pm.permission.Permission;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -416,7 +382,6 @@
 import com.android.server.utils.Watcher;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
-import dalvik.system.CloseGuard;
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
@@ -431,7 +396,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -442,10 +406,8 @@
 import java.lang.annotation.Target;
 import java.nio.charset.StandardCharsets;
 import java.security.DigestException;
-import java.security.DigestInputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
@@ -531,7 +493,7 @@
     private static final boolean DEBUG_PACKAGE_INFO = false;
     private static final boolean DEBUG_INTENT_MATCHING = false;
     public static final boolean DEBUG_PACKAGE_SCANNING = false;
-    private static final boolean DEBUG_VERIFY = false;
+    static final boolean DEBUG_VERIFY = false;
     public static final boolean DEBUG_PERMISSIONS = false;
     private static final boolean DEBUG_SHARED_LIBRARIES = false;
     public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
@@ -544,7 +506,7 @@
     public static final boolean DEBUG_DEXOPT = false;
 
     static final boolean DEBUG_ABI_SELECTION = false;
-    private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
+    public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_APP_DATA = false;
 
     /** REMOVE. According to Svet, this was only used to reset permissions during development. */
@@ -552,7 +514,7 @@
 
     private static final boolean HIDE_EPHEMERAL_APIS = false;
 
-    private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
+    static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -680,43 +642,10 @@
     private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS;
 
     /**
-     * Whether verification is enabled by default.
-     */
-    private static final boolean DEFAULT_VERIFY_ENABLE = true;
-
-    /**
-     * Whether integrity verification is enabled by default.
-     */
-    private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
-
-    /**
      * The default maximum time to wait for the verification agent to return in
      * milliseconds.
      */
-    private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
-
-    /**
-     * The default maximum time to wait for the integrity verification to return in
-     * milliseconds.
-     */
-    private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
-
-    /**
-     * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
-     * rollback within that period, the install will proceed without rollback enabled.
-     *
-     * <p>If flag value is negative, the default value will be assigned.
-     *
-     * Flag type: {@code long}
-     * Namespace: NAMESPACE_ROLLBACK
-     */
-    private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
-
-    /**
-     * The default duration to wait for rollback to be enabled in
-     * milliseconds.
-     */
-    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
+    static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
 
     /**
      * Default IncFs timeouts. Maximum values in IncFs is 1hr.
@@ -774,9 +703,23 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
     private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088;
 
+    /**
+     * Components of apps targeting Android T and above will stop receiving intents from
+     * external callers that do not match its declared intent filters.
+     *
+     * When an app registers an exported component in its manifest and adds an <intent-filter>,
+     * the component can be started by any intent - even those that do not match the intent filter.
+     * This has proven to be something that many developers find counterintuitive.
+     * Without checking the intent when the component is started, in some circumstances this can
+     * allow 3P apps to trigger internal-only functionality.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+    private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
+
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
-    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
+    static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
 
     private static final String PACKAGE_SCHEME = "package";
 
@@ -943,7 +886,7 @@
 
     boolean mFirstBoot;
 
-    private final boolean mIsEngBuild;
+    final boolean mIsEngBuild;
     private final boolean mIsUserDebugBuild;
     private final String mIncrementalVersion;
 
@@ -974,16 +917,11 @@
     @GuardedBy("mLock")
     final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
 
-    @GuardedBy("mLock")
-    private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
-
     private final ModuleInfoProvider mModuleInfoProvider;
 
-    private final ApexManager mApexManager;
+    final ApexManager mApexManager;
 
-    private final Injector mInjector;
-
-    private final SystemWrapper mSystemWrapper;
+    final Injector mInjector;
 
     /**
      * The list of all system partitions that may contain packages in ascending order of
@@ -1402,17 +1340,16 @@
         public ArrayMap<String, AndroidPackage> packages;
         public boolean enableFreeCacheV2;
         public int sdkVersion;
-        public SystemWrapper systemWrapper;
         public File appInstallDir;
         public File appLib32InstallDir;
         public boolean isEngBuild;
         public boolean isUserDebugBuild;
         public int sdkInt = Build.VERSION.SDK_INT;
-        public String incrementalVersion = Build.VERSION.INCREMENTAL;
+        public final String incrementalVersion = Build.VERSION.INCREMENTAL;
     }
 
     @Watched
-    private final AppsFilter mAppsFilter;
+    final AppsFilter mAppsFilter;
 
     final PackageParser2.Callback mPackageParserCallback;
 
@@ -1460,24 +1397,24 @@
 
     final ArtManagerService mArtManagerService;
 
-    private final PackageDexOptimizer mPackageDexOptimizer;
+    final PackageDexOptimizer mPackageDexOptimizer;
     // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package
     // is used by other apps).
     private final DexManager mDexManager;
 
-    private final ViewCompiler mViewCompiler;
+    final ViewCompiler mViewCompiler;
 
-    private AtomicInteger mNextMoveId = new AtomicInteger();
+    private final AtomicInteger mNextMoveId = new AtomicInteger();
     private final MoveCallbacks mMoveCallbacks;
 
     // Cache of users who need badging.
     private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
 
     /** Token for keys in mPendingVerification. */
-    private int mPendingVerificationToken = 0;
+    int mPendingVerificationToken = 0;
 
     /** Token for keys in mPendingEnableRollback. */
-    private int mPendingEnableRollbackToken = 0;
+    int mPendingEnableRollbackToken = 0;
 
     @Watched(manual = true)
     volatile boolean mSystemReady;
@@ -1510,7 +1447,7 @@
 
     /** Activity used to install instant applications */
     @Watched(manual = true)
-    private ActivityInfo mInstantAppInstallerActivity;
+    ActivityInfo mInstantAppInstallerActivity;
     @Watched(manual = true)
     private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
 
@@ -1518,7 +1455,7 @@
             mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
 
     // Internal interface for permission manager
-    private final PermissionManagerServiceInternal mPermissionManager;
+    final PermissionManagerServiceInternal mPermissionManager;
 
     @Watched
     private final ComponentResolver mComponentResolver;
@@ -1533,7 +1470,7 @@
 
     private Future<?> mPrepareAppDataFuture;
 
-    private final IncrementalManager mIncrementalManager;
+    final IncrementalManager mIncrementalManager;
 
     private final DefaultAppProvider mDefaultAppProvider;
 
@@ -1645,7 +1582,7 @@
     final UserManagerService mUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
-    private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
+    private final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
 
     // Recordkeeping of restore-after-install operations that are currently in flight
     // between the Package Manager and the Backup Manager
@@ -1671,31 +1608,6 @@
     // XML tags for backup/restore of various bits of state
     private static final String TAG_PREFERRED_BACKUP = "pa";
     private static final String TAG_DEFAULT_APPS = "da";
-    private static final String TAG_INTENT_FILTER_VERIFICATION = "iv";
-
-    private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup";
-    private static final String TAG_ALL_GRANTS = "rt-grants";
-    private static final String TAG_GRANT = "grant";
-    private static final String ATTR_PACKAGE_NAME = "pkg";
-
-    private static final String TAG_PERMISSION = "perm";
-    private static final String ATTR_PERMISSION_NAME = "name";
-    private static final String ATTR_IS_GRANTED = "g";
-    private static final String ATTR_USER_SET = "set";
-    private static final String ATTR_USER_FIXED = "fixed";
-    private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
-
-    // System/policy permission grants are not backed up
-    private static final int SYSTEM_RUNTIME_GRANT_MASK =
-            FLAG_PERMISSION_POLICY_FIXED
-            | FLAG_PERMISSION_SYSTEM_FIXED
-            | FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-
-    // And we back up these user-adjusted states
-    private static final int USER_RUNTIME_GRANT_MASK =
-            FLAG_PERMISSION_USER_SET
-            | FLAG_PERMISSION_USER_FIXED
-            | FLAG_PERMISSION_REVOKED_COMPAT;
 
     final @Nullable String mRequiredVerifierPackage;
     final @NonNull String mRequiredInstallerPackage;
@@ -1838,7 +1750,7 @@
     private final Watcher mWatcher = new Watcher() {
             @Override
                        public void onChange(@Nullable Watchable what) {
-                PackageManagerService.this.onChange(what);
+                PackageManagerService.onChange(what);
             }
         };
 
@@ -1959,7 +1871,7 @@
          */
         @Target({ ElementType.METHOD })
         @Retention(RetentionPolicy.RUNTIME)
-        public @interface LiveImplementation {
+        @interface LiveImplementation {
             // A Computer method must be annotated with one of the following values:
             //   MANDATORY - the method must be overridden in ComputerEngineLive.  The
             //     format of the override is a call to the super method, wrapped in a
@@ -2264,9 +2176,11 @@
                     false /* requireFullPermission */, false /* checkShell */,
                     "query intent activities");
             final String pkgName = intent.getPackage();
+            Intent originalIntent = null;
             ComponentName comp = intent.getComponent();
             if (comp == null) {
                 if (intent.getSelector() != null) {
+                    originalIntent = intent;
                     intent = intent.getSelector();
                     comp = intent.getComponent();
                 }
@@ -2276,8 +2190,9 @@
                     comp != null || pkgName != null /*onlyExposedExplicitly*/,
                     isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
                             flags));
+            List<ResolveInfo> list = Collections.emptyList();
+            boolean skipPostResolution = false;
             if (comp != null) {
-                final List<ResolveInfo> list = new ArrayList<>(1);
                 final ActivityInfo ai = getActivityInfo(comp, flags, userId);
                 if (ai != null) {
                     // When specifying an explicit component, we prevent the activity from being
@@ -2320,36 +2235,45 @@
                     if (!blockInstantResolution && !blockNormalResolution) {
                         final ResolveInfo ri = new ResolveInfo();
                         ri.activityInfo = ai;
+                        list = new ArrayList<>(1);
                         list.add(ri);
+                        applyEnforceIntentFilterMatching(
+                                mInjector.getCompatibility(), mComponentResolver,
+                                list, false, intent, resolvedType, filterCallingUid);
                     }
                 }
-
-                List<ResolveInfo> result = applyPostResolutionFilter(
-                        list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
-                        resolveForStart,
-                        userId, intent);
-                return result;
+            } else {
+                QueryIntentActivitiesResult lockedResult =
+                        queryIntentActivitiesInternalBody(
+                                intent, resolvedType, flags, filterCallingUid, userId,
+                                resolveForStart, allowDynamicSplits, pkgName, instantAppPkgName);
+                if (lockedResult.answer != null) {
+                    skipPostResolution = true;
+                    list = lockedResult.answer;
+                } else {
+                    if (lockedResult.addInstant) {
+                        String callingPkgName = getInstantAppPackageName(filterCallingUid);
+                        boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
+                        lockedResult.result = maybeAddInstantAppInstaller(
+                                lockedResult.result, intent, resolvedType, flags,
+                                userId, resolveForStart, isRequesterInstantApp);
+                    }
+                    if (lockedResult.sortResult) {
+                        lockedResult.result.sort(RESOLVE_PRIORITY_SORTER);
+                    }
+                    list = lockedResult.result;
+                }
             }
 
-            QueryIntentActivitiesResult lockedResult =
-                    queryIntentActivitiesInternalBody(
-                        intent, resolvedType, flags, filterCallingUid, userId, resolveForStart,
-                        allowDynamicSplits, pkgName, instantAppPkgName);
-            if (lockedResult.answer != null) {
-                return lockedResult.answer;
+            if (originalIntent != null) {
+                // We also have to ensure all components match the original intent
+                applyEnforceIntentFilterMatching(
+                        mInjector.getCompatibility(), mComponentResolver,
+                        list, false, originalIntent, resolvedType, filterCallingUid);
             }
 
-            if (lockedResult.addInstant) {
-                String callingPkgName = getInstantAppPackageName(filterCallingUid);
-                boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
-                lockedResult.result = maybeAddInstantAppInstaller(lockedResult.result, intent,
-                        resolvedType, flags, userId, resolveForStart, isRequesterInstantApp);
-            }
-            if (lockedResult.sortResult) {
-                Collections.sort(lockedResult.result, RESOLVE_PRIORITY_SORTER);
-            }
-            return applyPostResolutionFilter(
-                    lockedResult.result, instantAppPkgName, allowDynamicSplits, filterCallingUid,
+            return skipPostResolution ? list : applyPostResolutionFilter(
+                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid,
                     resolveForStart, userId, intent);
         }
 
@@ -2372,15 +2296,17 @@
             final String instantAppPkgName = getInstantAppPackageName(callingUid);
             flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
                     false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
+            Intent originalIntent = null;
             ComponentName comp = intent.getComponent();
             if (comp == null) {
                 if (intent.getSelector() != null) {
+                    originalIntent = intent;
                     intent = intent.getSelector();
                     comp = intent.getComponent();
                 }
             }
+            List<ResolveInfo> list = Collections.emptyList();
             if (comp != null) {
-                final List<ResolveInfo> list = new ArrayList<>(1);
                 final ServiceInfo si = getServiceInfo(comp, flags, userId);
                 if (si != null) {
                     // When specifying an explicit component, we prevent the service from being
@@ -2413,14 +2339,26 @@
                     if (!blockInstantResolution && !blockNormalResolution) {
                         final ResolveInfo ri = new ResolveInfo();
                         ri.serviceInfo = si;
+                        list = new ArrayList<>(1);
                         list.add(ri);
+                        applyEnforceIntentFilterMatching(
+                                mInjector.getCompatibility(), mComponentResolver,
+                                list, false, intent, resolvedType, callingUid);
                     }
                 }
-                return list;
+            } else {
+                list = queryIntentServicesInternalBody(intent, resolvedType, flags,
+                        userId, callingUid, instantAppPkgName);
             }
 
-            return queryIntentServicesInternalBody(intent, resolvedType, flags,
-                    userId, callingUid, instantAppPkgName);
+            if (originalIntent != null) {
+                // We also have to ensure all components match the original intent
+                applyEnforceIntentFilterMatching(
+                        mInjector.getCompatibility(), mComponentResolver,
+                        list, false, originalIntent, resolvedType, callingUid);
+            }
+
+            return list;
         }
 
         protected @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
@@ -3969,10 +3907,8 @@
                     return true;
                 }
                 // TODO(b/122900055) Change/Remove this and replace with new permission role.
-                if (mAppPredictionServicePackage != null
-                        && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
-                    return true;
-                }
+                return mAppPredictionServicePackage != null
+                        && isCallerSameApp(mAppPredictionServicePackage, callingUid);
             }
             return false;
         }
@@ -4074,10 +4010,7 @@
             if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
                 return true;
             }
-            if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) {
-                return true;
-            }
-            return false;
+            return isComponentVisibleToInstantApp(component, TYPE_PROVIDER);
         }
 
         public final boolean isComponentVisibleToInstantApp(
@@ -4314,11 +4247,8 @@
             final String instantAppPkgName = getInstantAppPackageName(callingUid);
             final boolean callerIsInstantApp = instantAppPkgName != null;
             if (ps == null) {
-                if (callerIsInstantApp) {
-                    // pretend the application exists, but, needs to be filtered
-                    return true;
-                }
-                return false;
+                // pretend the application exists, but, needs to be filtered
+                return callerIsInstantApp;
             }
             // if the target and caller are the same application, don't filter
             if (isCallerSameApp(ps.name, callingUid)) {
@@ -5046,13 +4976,13 @@
         // a live computer.
         private final AtomicInteger mReusedLive = new AtomicInteger(0);
 
-        private PackageManagerService mService;
+        private final PackageManagerService mService;
         ComputerTracker(PackageManagerService s) {
             mService = s;
         }
 
         private ThreadComputer live() {
-            ThreadComputer current = mService.sThreadComputer.get();
+            ThreadComputer current = sThreadComputer.get();
             if (current.mRefCount > 0) {
                 current.acquire();
                 mReusedLive.incrementAndGet();
@@ -5063,7 +4993,7 @@
         }
 
         private ThreadComputer snapshot() {
-            ThreadComputer current = mService.sThreadComputer.get();
+            ThreadComputer current = sThreadComputer.get();
             if (current.mRefCount > 0) {
                 current.acquire();
                 mReusedSnapshot.incrementAndGet();
@@ -5623,13 +5553,13 @@
     // set from outside classes.  The attribute may be set to true anywhere, although it
     // should only be set true while holding mLock.  However, the attribute id guaranteed
     // to be set false only while mLock and mSnapshotLock are both held.
-    private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
+    private static final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true);
     // The package manager that is using snapshots.
     private static PackageManagerService sSnapshotConsumer = null;
     // If true, the snapshot is corked.  Do not create a new snapshot but use the live
     // computer.  This throttles snapshot creation during periods of churn in Package
     // Manager.
-    private static AtomicInteger sSnapshotCorked = new AtomicInteger(0);
+    private static final AtomicInteger sSnapshotCorked = new AtomicInteger(0);
 
     /**
      * This class records the Computer being used by a thread and the Computer's reference
@@ -5657,10 +5587,8 @@
             }
         }
     }
-    private static ThreadLocal<ThreadComputer> sThreadComputer = new ThreadLocal<>() {
-            @Override protected ThreadComputer initialValue() {
-                return new ThreadComputer();
-            }};
+    private static final ThreadLocal<ThreadComputer> sThreadComputer =
+            ThreadLocal.withInitial(ThreadComputer::new);
 
     /**
      * This lock is used to make reads from {@link #sSnapshotInvalid} and
@@ -5834,10 +5762,10 @@
                     break;
                 }
                 case SEND_PENDING_BROADCAST: {
-                    String packages[];
-                    ArrayList<String> components[];
+                    String[] packages;
+                    ArrayList<String>[] components;
                     int size = 0;
-                    int uids[];
+                    int[] uids;
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                     synchronized (mLock) {
                         size = mPendingBroadcasts.size();
@@ -5883,8 +5811,8 @@
                     final boolean didRestore = (msg.arg2 != 0);
                     mRunningInstalls.delete(msg.arg1);
 
-                    if (data != null && data.res.freezer != null) {
-                        data.res.freezer.close();
+                    if (data != null && data.res.mFreezer != null) {
+                        data.res.mFreezer.close();
                     }
 
                     if (data != null && data.mPostInstallRunnable != null) {
@@ -5893,19 +5821,19 @@
                         InstallArgs args = data.args;
                         PackageInstalledInfo parentRes = data.res;
 
-                        final boolean killApp = (args.installFlags
+                        final boolean killApp = (args.mInstallFlags
                                 & PackageManager.INSTALL_DONT_KILL_APP) == 0;
-                        final boolean virtualPreload = ((args.installFlags
+                        final boolean virtualPreload = ((args.mInstallFlags
                                 & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
 
                         handlePackagePostInstall(parentRes, killApp, virtualPreload,
-                                didRestore, args.installSource.installerPackageName, args.observer,
-                                args.mDataLoaderType);
+                                didRestore, args.mInstallSource.installerPackageName,
+                                args.mObserver, args.mDataLoaderType);
 
                         // Log tracing if needed
-                        if (args.traceMethod != null) {
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
-                                    args.traceCookie);
+                        if (args.mTraceMethod != null) {
+                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod,
+                                    args.mTraceCookie);
                         }
                     } else if (DEBUG_INSTALL) {
                         // No post-install when we run restore from installExistingPackageForUser
@@ -5964,7 +5892,7 @@
                     if ((state != null) && !state.isVerificationComplete()
                             && !state.timeoutExtended()) {
                         final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                         String errorMsg = "Verification timed out for " + originUri;
                         Slog.i(TAG, errorMsg);
@@ -6006,7 +5934,7 @@
 
                     if (state != null && !state.isIntegrityVerificationComplete()) {
                         final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                         String errorMsg = "Integrity verification timed out for " + originUri;
                         Slog.i(TAG, errorMsg);
@@ -6053,7 +5981,7 @@
 
                     if (state.isVerificationComplete()) {
                         final VerificationParams params = state.getVerificationParams();
-                        final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                         if (state.isInstallAllowed()) {
                             broadcastPackageVerified(verificationId, originUri,
@@ -6088,7 +6016,7 @@
 
                     final int response = (Integer) msg.obj;
                     final VerificationParams params = state.getVerificationParams();
-                    final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                    final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                     state.setIntegrityVerificationResult(response);
 
@@ -6134,7 +6062,7 @@
                     mPendingEnableRollback.remove(enableRollbackToken);
 
                     if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
-                        final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
                         Slog.w(TAG, "Failed to enable rollback for " + originUri);
                         Slog.w(TAG, "Continuing with installation of " + originUri);
                     }
@@ -6151,7 +6079,7 @@
                     final VerificationParams params =
                             mPendingEnableRollback.get(enableRollbackToken);
                     if (params != null) {
-                        final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
+                        final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile);
 
                         Slog.w(TAG, "Enable rollback timed out for " + originUri);
                         mPendingEnableRollback.remove(enableRollbackToken);
@@ -6192,20 +6120,21 @@
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp,
             boolean virtualPreload, boolean launchedForRestore, String installerPackage,
             IPackageInstallObserver2 installObserver, int dataLoaderType) {
-        boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
-        final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
-        final String packageName = res.name;
+        boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
+        final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
+        final String packageName = res.mName;
         final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
         final boolean removedBeforeUpdate = (pkgSetting == null)
-                || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath()));
+                || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(
+                        res.mPkg.getPath()));
         if (succeeded && removedBeforeUpdate) {
             Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
                     + "could be executed");
-            res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED;
-            res.returnMsg = "Package was removed before install could complete.";
+            res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
+            res.mReturnMsg = "Package was removed before install could complete.";
 
             // Remove the update failed package's older resources safely now
-            InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+            InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
             if (args != null) {
                 synchronized (mInstallLock) {
                     args.doPostDeleteLI(true);
@@ -6220,19 +6149,19 @@
             mPerUidReadTimeoutsCache = null;
 
             // Send the removed broadcasts
-            if (res.removedInfo != null) {
-                res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
+            if (res.mRemovedInfo != null) {
+                res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
             }
 
             final String installerPackageName =
-                    res.installerPackageName != null
-                            ? res.installerPackageName
-                            : res.removedInfo != null
-                                    ? res.removedInfo.installerPackageName
+                    res.mInstallerPackageName != null
+                            ? res.mInstallerPackageName
+                            : res.mRemovedInfo != null
+                                    ? res.mRemovedInfo.mInstallerPackageName
                                     : null;
 
             synchronized (mLock) {
-                mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
+                mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers);
             }
 
             // Determine the set of users who are adding this package for
@@ -6241,10 +6170,9 @@
             int[] firstInstantUserIds = EMPTY_INT_ARRAY;
             int[] updateUserIds = EMPTY_INT_ARRAY;
             int[] instantUserIds = EMPTY_INT_ARRAY;
-            final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
-            final PackageSetting ps = pkgSetting;
-            for (int newUser : res.newUsers) {
-                final boolean isInstantApp = ps.getInstantApp(newUser);
+            final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0;
+            for (int newUser : res.mNewUsers) {
+                final boolean isInstantApp = pkgSetting.getInstantApp(newUser);
                 if (allNewUsers) {
                     if (isInstantApp) {
                         firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser);
@@ -6254,7 +6182,7 @@
                     continue;
                 }
                 boolean isNew = true;
-                for (int origUser : res.origUsers) {
+                for (int origUser : res.mOrigUsers) {
                     if (origUser == newUser) {
                         isNew = false;
                         break;
@@ -6276,20 +6204,20 @@
             }
 
             // Send installed broadcasts if the package is not a static shared lib.
-            if (res.pkg.getStaticSharedLibName() == null) {
-                mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath());
+            if (res.mPkg.getStaticSharedLibName() == null) {
+                mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
 
                 // Send added for users that see the package for the first time
                 // sendPackageAddedForNewUsers also deals with system apps
-                int appId = UserHandle.getAppId(res.uid);
-                boolean isSystem = res.pkg.isSystem();
+                int appId = UserHandle.getAppId(res.mUid);
+                boolean isSystem = res.mPkg.isSystem();
                 sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                         virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
                         dataLoaderType);
 
                 // Send added for users that don't see the package for the first time
                 Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, res.uid);
+                extras.putInt(Intent.EXTRA_UID, res.mUid);
                 if (update) {
                     extras.putBoolean(Intent.EXTRA_REPLACING, true);
                 }
@@ -6299,7 +6227,7 @@
 
                 synchronized (mLock) {
                     newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                            getPackageSettingInternal(res.name, Process.SYSTEM_UID),
+                            getPackageSettingInternal(res.mName, Process.SYSTEM_UID),
                             updateUserIds, mSettings.getPackagesLocked());
                 }
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -6337,7 +6265,7 @@
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                             packageName, extras, 0 /*flags*/,
                             null /*targetPackage*/, null /*finishedReceiver*/,
-                            updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList,
+                            updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
                             null);
                     if (installerPackageName != null) {
                         sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
@@ -6358,7 +6286,7 @@
                             null /*broadcastAllowList*/,
                             getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED)
                                     .toBundle());
-                } else if (launchedForRestore && !res.pkg.isSystem()) {
+                } else if (launchedForRestore && !res.mPkg.isSystem()) {
                     // First-install and we did a restore, so we're responsible for the
                     // first-launch broadcast.
                     if (DEBUG_BACKUP) {
@@ -6370,15 +6298,15 @@
                 }
 
                 // Send broadcast package appeared if external for all users
-                if (res.pkg.isExternalStorage()) {
+                if (res.mPkg.isExternalStorage()) {
                     if (!update) {
                         final StorageManager storage = mInjector.getSystemService(
                                 StorageManager.class);
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
-                                        res.pkg.getStorageUuid().toString());
+                                        res.mPkg.getStorageUuid().toString());
                         int packageExternalStorageType =
-                                getPackageExternalStorageType(volume, res.pkg.isExternalStorage());
+                                getPackageExternalStorageType(volume, res.mPkg.isExternalStorage());
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
                             FrameworkStatsLog.write(
@@ -6387,17 +6315,16 @@
                         }
                     }
                     if (DEBUG_INSTALL) {
-                        Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
+                        Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
                     }
-                    final int[] uidArray = new int[]{res.pkg.getUid()};
+                    final int[] uidArray = new int[]{res.mPkg.getUid()};
                     ArrayList<String> pkgList = new ArrayList<>(1);
                     pkgList.add(packageName);
                     sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                 }
-            } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
-                int[] allUsers = mInjector.getUserManagerService().getUserIds();
-                for (int i = 0; i < res.libraryConsumers.size(); i++) {
-                    AndroidPackage pkg = res.libraryConsumers.get(i);
+            } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
+                for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
+                    AndroidPackage pkg = res.mLibraryConsumers.get(i);
                     // send broadcast that all consumers of the static shared library have changed
                     sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
                             new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
@@ -6409,14 +6336,14 @@
             if (firstUserIds != null && firstUserIds.length > 0) {
                 for (int userId : firstUserIds) {
                     restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                            pkgSetting.getInstallReason(userId), userId);
+                            userId);
                 }
             }
 
             if (allNewUsers && !update) {
-                notifyPackageAdded(packageName, res.uid);
+                notifyPackageAdded(packageName, res.mUid);
             } else {
-                notifyPackageChanged(packageName, res.uid);
+                notifyPackageChanged(packageName, res.mUid);
             }
 
             // Log current value of "unknown sources" setting
@@ -6424,7 +6351,7 @@
                     getUnknownSourcesSettings());
 
             // Remove the replaced package's older resources safely now
-            InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+            InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
             if (args != null) {
                 if (!killApp) {
                     // If we didn't kill the app, defer the deletion of code/resource files, since
@@ -6483,7 +6410,7 @@
         }
     }
 
-    private void notifyInstallObserver(String packageName) {
+    void notifyInstallObserver(String packageName) {
         Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
                 mNoKillInstallObservers.remove(packageName);
 
@@ -6492,13 +6419,13 @@
         }
     }
 
-    private void notifyInstallObserver(PackageInstalledInfo info,
+    void notifyInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 installObserver) {
         if (installObserver != null) {
             try {
                 Bundle extras = extrasForInstallResult(info);
-                installObserver.onPackageInstalled(info.name, info.returnCode,
-                        info.returnMsg, extras);
+                installObserver.onPackageInstalled(info.mName, info.mReturnCode,
+                        info.mReturnMsg, extras);
             } catch (RemoteException e) {
                 Slog.i(TAG, "Observer no longer exists.");
             }
@@ -6512,7 +6439,7 @@
 
     private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 observer) {
-        String packageName = info.pkg.getPackageName();
+        String packageName = info.mPkg.getPackageName();
         mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
         Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
         mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -6617,7 +6544,7 @@
         return StorageEnums.UNKNOWN;
     }
 
-    private StorageEventListener mStorageListener = new StorageEventListener() {
+    private final StorageEventListener mStorageListener = new StorageEventListener() {
         @Override
         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
             if (vol.type == VolumeInfo.TYPE_PRIVATE) {
@@ -6671,19 +6598,19 @@
 
     Bundle extrasForInstallResult(PackageInstalledInfo res) {
         Bundle extras = null;
-        switch (res.returnCode) {
+        switch (res.mReturnCode) {
             case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
                 extras = new Bundle();
                 extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
-                        res.origPermission);
+                        res.mOrigPermission);
                 extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
-                        res.origPackage);
+                        res.mOrigPackage);
                 break;
             }
             case PackageManager.INSTALL_SUCCEEDED: {
                 extras = new Bundle();
                 extras.putBoolean(Intent.EXTRA_REPLACING,
-                        res.removedInfo != null && res.removedInfo.removedPackage != null);
+                        res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null);
                 break;
             }
         }
@@ -6872,7 +6799,7 @@
      * reasons. This simply requests that the copy takes place and awaits confirmation of its
      * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy.
      */
-    private static void requestCopyPreoptedFiles(Injector injector) {
+    private static void requestCopyPreoptedFiles() {
         final int WAIT_TIME_MS = 100;
         final String CP_PREOPT_PROPERTY = "sys.cppreopt";
         if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
@@ -7047,7 +6974,6 @@
         mPackages.putAll(testParams.packages);
         mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
         mSdkVersion = testParams.sdkVersion;
-        mSystemWrapper = testParams.systemWrapper;
         mAppInstallDir = testParams.appInstallDir;
         mAppLib32InstallDir = testParams.appLib32InstallDir;
         mIsEngBuild = testParams.isEngBuild;
@@ -7077,7 +7003,6 @@
         LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                 SystemClock.uptimeMillis());
-        mSystemWrapper = injector.getSystemWrapper();
 
         mContext = injector.getContext();
         mFactoryTest = factoryTest;
@@ -7260,7 +7185,7 @@
             mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions);
 
             if (!mOnlyCore && mFirstBoot) {
-                requestCopyPreoptedFiles(mInjector);
+                requestCopyPreoptedFiles();
             }
 
             String customResolverActivityName = Resources.getSystem().getString(
@@ -8142,7 +8067,7 @@
     }
 
     @GuardedBy("mLock")
-    private void updateInstantAppInstallerLocked(String modifiedPackage) {
+    void updateInstantAppInstallerLocked(String modifiedPackage) {
         // we're only interested in updating the installer appliction when 1) it's not
         // already set or 2) the modified package is the installer
         if (mInstantAppInstallerActivity != null
@@ -8252,7 +8177,7 @@
 
         final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
                 MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
+                UserHandle.USER_SYSTEM, Binder.getCallingUid());
         if (matches.size() == 1) {
             return matches.get(0).getComponentInfo().packageName;
         } else if (matches.size() == 0) {
@@ -8348,7 +8273,7 @@
 
         final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
                 MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
+                UserHandle.USER_SYSTEM, Binder.getCallingUid());
         ResolveInfo best = null;
         final int N = matches.size();
         for (int i = 0; i < N; i++) {
@@ -8376,7 +8301,7 @@
         Intent intent = new Intent(Intent.ACTION_DOMAINS_NEED_VERIFICATION);
         List<ResolveInfo> matches = queryIntentReceiversInternal(intent, null,
                 MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
+                UserHandle.USER_SYSTEM, Binder.getCallingUid());
         ResolveInfo best = null;
         final int N = matches.size();
         for (int i = 0; i < N; i++) {
@@ -8411,11 +8336,7 @@
             return null;
         }
         synchronized (mLock) {
-            final ComponentName instantAppResolver = getInstantAppResolverLPr();
-            if (instantAppResolver == null) {
-                return null;
-            }
-            return instantAppResolver;
+            return getInstantAppResolverLPr();
         }
     }
 
@@ -8671,16 +8592,6 @@
                 flags, filterCallingUid, userId);
     }
 
-    private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
-        return mComputer.isComponentVisibleToInstantApp(component);
-    }
-
-    private boolean isComponentVisibleToInstantApp(
-            @Nullable ComponentName component, @ComponentType int type) {
-        return mComputer.isComponentVisibleToInstantApp(
-            component, type);
-    }
-
     /**
      * Returns whether or not access to the application should be filtered.
      * <p>
@@ -8999,14 +8910,13 @@
             if (freeBytesRequired > 0) {
                 smInternal.freeCache(volumeUuid, freeBytesRequired);
             }
-            if (file.getUsableSpace() >= bytes) return;
         } else {
             try {
                 mInstaller.freeCache(volumeUuid, bytes, 0, 0);
             } catch (InstallerException ignored) {
             }
-            if (file.getUsableSpace() >= bytes) return;
         }
+        if (file.getUsableSpace() >= bytes) return;
 
         throw new IOException("Failed to free " + bytes + " on storage device at " + file);
     }
@@ -9020,7 +8930,6 @@
         final long now = System.currentTimeMillis();
 
         synchronized (mLock) {
-            final int[] allUsers = mUserManager.getUserIds();
             final int libCount = mSharedLibraries.size();
             for (int i = 0; i < libCount; i++) {
                 final WatchedLongSparseArray<SharedLibraryInfo> versionedLib
@@ -9133,14 +9042,6 @@
                 wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
     }
 
-    private int updateFlagsForResolve(int flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean onlyExposedExplicitly,
-            boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
-        return mComputer.updateFlagsForResolve(flags, userId, callingUid,
-                wantInstantApps, onlyExposedExplicitly,
-                isImplicitImageCaptureIntentAndNotSetByDpc);
-    }
-
     @Override
     public int getTargetSdkVersion(String packageName)  {
         synchronized (mLock) {
@@ -9560,7 +9461,7 @@
     }
 
     @GuardedBy("mLock")
-    private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
+    void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) {
         for (int i = userList.length - 1; i >= 0; --i) {
             final int userId = userList[i];
             SparseArray<String> changedPackages = mChangedPackages.get(userId);
@@ -9914,7 +9815,7 @@
      * external storage) is less than the version where package signatures
      * were updated, return true.
      */
-    private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
+    boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
         return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
@@ -9922,7 +9823,7 @@
         return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
     }
 
-    private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
+    boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
         return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
@@ -10295,7 +10196,7 @@
                 userId);
         // Find any earlier preferred or last chosen entries and nuke them
         findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, 0, false, true, false, userId);
+                intent, resolvedType, flags, query, false, true, false, userId);
         // Add the new activity as the last chosen for this filter
         addPreferredActivity(filter, match, null, activity, false, userId,
                 "Setting last chosen", false);
@@ -10311,7 +10212,7 @@
         final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                 userId);
         return findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, 0, false, false, false, userId);
+                intent, resolvedType, flags, query, false, false, false, userId);
     }
 
     private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
@@ -10353,7 +10254,7 @@
                 // If we have saved a preference for a preferred activity for
                 // this Intent, use that.
                 ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
-                        flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered);
+                        flags, query, true, false, debug, userId, queryMayBeFiltered);
                 if (ri != null) {
                     return ri;
                 }
@@ -10530,17 +10431,17 @@
     }
 
     ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
-            List<ResolveInfo> query, int priority, boolean always,
+            List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         return findPreferredActivityNotLocked(
-                intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId,
+                intent, resolvedType, flags, query, always, removeMatches, debug, userId,
                 UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
     }
 
     // TODO: handle preferred activities missing while user has amnesia
     /** <b>must not hold {@link #mLock}</b> */
     ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
-            List<ResolveInfo> query, int priority, boolean always,
+            List<ResolveInfo> query, boolean always,
             boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
         if (Thread.holdsLock(mLock)) {
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
@@ -10848,16 +10749,6 @@
                 filterCallingUid, userId, resolveForStart, allowDynamicSplits);
     }
 
-    private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
-            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
-            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
-            String instantAppPkgName) {
-        return mComputer.queryIntentActivitiesInternalBody(
-            intent, resolvedType, flags, filterCallingUid, userId,
-            resolveForStart, allowDynamicSplits, pkgName,
-            instantAppPkgName);
-    }
-
     private static class CrossProfileDomainInfo {
         /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */
         ResolveInfo resolveInfo;
@@ -11089,30 +10980,32 @@
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
             String resolvedType, int flags, int userId) {
-        return new ParceledListSlice<>(
-                queryIntentReceiversInternal(intent, resolvedType, flags, userId,
-                        false /*allowDynamicSplits*/));
+        return new ParceledListSlice<>(queryIntentReceiversInternal(intent, resolvedType,
+                flags, userId, Binder.getCallingUid()));
     }
 
+    // In this method, we have to know the actual calling UID, but in some cases Binder's
+    // call identity is removed, so the UID has to be passed in explicitly.
     private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
-            String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
+            String resolvedType, int flags, int userId, int filterCallingUid) {
         if (!mUserManager.exists(userId)) return Collections.emptyList();
-        final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
+        enforceCrossUserPermission(filterCallingUid, userId, false /*requireFullPermission*/,
                 false /*checkShell*/, "query intent receivers");
-        final String instantAppPkgName = getInstantAppPackageName(callingUid);
-        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
+        final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
+        flags = updateFlagsForResolve(flags, userId, filterCallingUid, false /*includeInstantApps*/,
                 isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
                         flags));
+        Intent originalIntent = null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
+                originalIntent = intent;
                 intent = intent.getSelector();
                 comp = intent.getComponent();
             }
         }
+        List<ResolveInfo> list = Collections.emptyList();
         if (comp != null) {
-            final List<ResolveInfo> list = new ArrayList<>(1);
             final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
             if (ai != null) {
                 // When specifying an explicit component, we prevent the activity from being
@@ -11148,40 +11041,44 @@
                 if (!blockResolution) {
                     ResolveInfo ri = new ResolveInfo();
                     ri.activityInfo = ai;
+                    list = new ArrayList<>(1);
                     list.add(ri);
+                    applyEnforceIntentFilterMatching(
+                            mInjector.getCompatibility(), mComponentResolver,
+                            list, true, intent, resolvedType, filterCallingUid);
                 }
             }
-            return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
-                    intent);
+        } else {
+            // reader
+            synchronized (mLock) {
+                String pkgName = intent.getPackage();
+                if (pkgName == null) {
+                    final List<ResolveInfo> result =
+                            mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
+                    if (result != null) {
+                        list = result;
+                    }
+                }
+                final AndroidPackage pkg = mPackages.get(pkgName);
+                if (pkg != null) {
+                    final List<ResolveInfo> result = mComponentResolver.queryReceivers(
+                            intent, resolvedType, flags, pkg.getReceivers(), userId);
+                    if (result != null) {
+                        list = result;
+                    }
+                }
+            }
         }
 
-        // reader
-        synchronized (mLock) {
-            String pkgName = intent.getPackage();
-            if (pkgName == null) {
-                final List<ResolveInfo> result =
-                        mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
-                if (result == null) {
-                    return Collections.emptyList();
-                }
-                return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
-                        intent);
-            }
-            final AndroidPackage pkg = mPackages.get(pkgName);
-            if (pkg != null) {
-                final List<ResolveInfo> result = mComponentResolver.queryReceivers(
-                        intent, resolvedType, flags, pkg.getReceivers(), userId);
-                if (result == null) {
-                    return Collections.emptyList();
-                }
-                return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
-                        intent);
-            }
-            return Collections.emptyList();
+        if (originalIntent != null) {
+            // We also have to ensure all components match the original intent
+            applyEnforceIntentFilterMatching(
+                    mInjector.getCompatibility(), mComponentResolver,
+                    list, true, originalIntent, resolvedType, filterCallingUid);
         }
+
+        return applyPostResolutionFilter(
+                list, instantAppPkgName, false, filterCallingUid, false, userId, intent);
     }
 
     @Override
@@ -11223,6 +11120,68 @@
                 includeInstantApps);
     }
 
+    // Static to give access to ComputeEngine
+    private static void applyEnforceIntentFilterMatching(
+            PlatformCompat compat, ComponentResolver resolver,
+            List<ResolveInfo> resolveInfos, boolean isReceiver,
+            Intent intent, String resolvedType, int filterCallingUid) {
+        // Do not enforce filter matching when the caller is system or root.
+        // see ActivityManager#checkComponentPermission(String, int, int, boolean)
+        if (filterCallingUid == Process.ROOT_UID || filterCallingUid == Process.SYSTEM_UID) {
+            return;
+        }
+
+        final Printer logPrinter = DEBUG_INTENT_MATCHING
+                ? new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM)
+                : null;
+
+        for (int i = resolveInfos.size() - 1; i >= 0; --i) {
+            final ComponentInfo info = resolveInfos.get(i).getComponentInfo();
+
+            // Do not enforce filter matching when the caller is the same app
+            if (info.applicationInfo.uid == filterCallingUid) {
+                continue;
+            }
+
+            // Only enforce filter matching if target app's target SDK >= T
+            if (!compat.isChangeEnabledInternal(
+                    ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS, info.applicationInfo)) {
+                continue;
+            }
+
+            final ParsedMainComponent comp;
+            if (info instanceof ActivityInfo) {
+                if (isReceiver) {
+                    comp = resolver.getReceiver(info.getComponentName());
+                } else {
+                    comp = resolver.getActivity(info.getComponentName());
+                }
+            } else if (info instanceof ServiceInfo) {
+                comp = resolver.getService(info.getComponentName());
+            } else {
+                // This shall never happen
+                throw new IllegalArgumentException("Unsupported component type");
+            }
+
+            if (comp.getIntents().isEmpty()) {
+                continue;
+            }
+
+            final boolean match = comp.getIntents().stream().anyMatch(
+                    f -> IntentResolver.intentMatchesFilter(f, intent, resolvedType));
+            if (!match) {
+                Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
+                Slog.w(TAG, "Access blocked: " + comp.getComponentName());
+                if (DEBUG_INTENT_MATCHING) {
+                    Slog.v(TAG, "Component intent filters:");
+                    comp.getIntents().forEach(f -> f.dump(logPrinter, "  "));
+                    Slog.v(TAG, "-----------------------------");
+                }
+                resolveInfos.remove(i);
+            }
+        }
+    }
+
     @Override
     public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
             String resolvedType, int flags, int userId) {
@@ -11981,7 +11940,7 @@
           return;
         }
 
-        clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+        clearAppProfilesLIF(pkg);
         if (DEBUG_INSTALL) {
             Slog.d(TAG, originalPkgSetting.name
                   + " clear profile due to version change "
@@ -12155,11 +12114,12 @@
                             null, disabledPkgSetting /* pkgSetting */,
                             null /* disabledPkgSetting */, null /* originalPkgSetting */,
                             null, parseFlags, scanFlags, isPlatformPackage, user, null);
-                    applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true);
+                    applyPolicy(parsedPackage, scanFlags, mPlatformPackage, true);
                     final ScanResult scanResult =
                             scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
-                    if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
-                        scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
+                    if (scanResult.mExistingSettingCopied
+                            && scanResult.mRequest.mPkgSetting != null) {
+                        scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting);
                     }
                 }
             }
@@ -12206,7 +12166,7 @@
             // for the package. Which means it needs to be finalized here to cache derived fields.
             // This is relevant for cases where the disabled system package is used for flags or
             // other metadata.
-            ((ParsedPackage) parsedPackage).hideAsFinal();
+            parsedPackage.hideAsFinal();
             throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
                     + " at " + parsedPackage.getPath() + " ignored: updated version "
                     + pkgSetting.versionCode + " better than this "
@@ -12258,7 +12218,7 @@
                         parsedPackage.getPackageName(),
                         "scanPackageInternalLI")) {
                     deletePackageLIF(parsedPackage.getPackageName(), null, true,
-                            mUserManager.getUserIds(), 0, null, false, null);
+                            mUserManager.getUserIds(), 0, null, false);
                 }
                 pkgSetting = null;
             } else if (newPkgVersionGreater) {
@@ -12295,11 +12255,11 @@
 
         final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
-        if (scanResult.success) {
+        if (scanResult.mSuccess) {
             synchronized (mLock) {
                 boolean appIdCreated = false;
                 try {
-                    final String pkgName = scanResult.pkgSetting.name;
+                    final String pkgName = scanResult.mPkgSetting.name;
                     final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
                             new ReconcileRequest(
                                     Collections.singletonMap(pkgName, scanResult),
@@ -12331,19 +12291,17 @@
             if (pkgSetting != null && pkgSetting.isPackageLoading()) {
                 // Continue monitoring loading progress of active incremental packages
                 final IncrementalStatesCallback incrementalStatesCallback =
-                        new IncrementalStatesCallback(parsedPackage.getPackageName(),
-                                UserHandle.getUid(UserHandle.USER_ALL, pkgSetting.appId),
-                                getInstalledUsers(pkgSetting, UserHandle.USER_ALL));
+                        new IncrementalStatesCallback(parsedPackage.getPackageName(), this);
                 pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback);
                 mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(),
-                        new IncrementalProgressListener(parsedPackage.getPackageName()));
+                        new IncrementalProgressListener(parsedPackage.getPackageName(), this));
             }
         }
-        return scanResult.pkgSetting.pkg;
+        return scanResult.mPkgSetting.pkg;
     }
 
     // TODO:(b/135203078): Move to parsing
-    private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
+    static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
         // Derive the new package synthetic package name
         parsedPackage.setPackageName(toStaticSharedLibraryPackageName(
                 parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibVersion()));
@@ -12354,13 +12312,6 @@
         return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
     }
 
-    static String fixProcessName(String defProcessName, String processName) {
-        if (processName == null) {
-            return defProcessName;
-        }
-        return processName;
-    }
-
     /**
      * Enforces that only the system UID or root's UID can call a method exposed
      * via Binder.
@@ -12403,24 +12354,6 @@
     }
 
     /**
-     * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
-     * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
-     *
-     * @param checkShell whether to prevent shell from access if there's a debugging restriction
-     * @param requirePermissionWhenSameUser When {@code true}, still require the cross user
-     *                                      permission to be held even if the callingUid and userId
-     *                                      reference the same user.
-     * @param message the message to log on security exception
-     */
-    private void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
-            boolean requireFullPermission, boolean checkShell,
-            boolean requirePermissionWhenSameUser, String message) {
-        mComputer.enforceCrossUserPermission(callingUid, userId,
-                requireFullPermission, checkShell,
-                requirePermissionWhenSameUser, message);
-    }
-
-    /**
      * Checks if the request is from the system or an app that has the appropriate cross-user
      * permissions defined as follows:
      * <ul>
@@ -12440,10 +12373,6 @@
                 requireFullPermission, checkShell, message);
     }
 
-    private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
-        return mComputer.isSameProfileGroup(callerUserId, userId);
-    }
-
     private static String buildInvalidCrossUserPermissionMessage(int callingUid,
             @UserIdInt int userId, String message, boolean requireFullPermission) {
         StringBuilder builder = new StringBuilder();
@@ -13095,7 +13024,7 @@
         return versionedLib.get(version);
     }
 
-    private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
+    SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
         WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
                 pkg.getStaticSharedLibName());
         if (versionedLib == null) {
@@ -13115,13 +13044,12 @@
         return null;
     }
 
-
     @Nullable
-    private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+    PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
         PackageSetting sharedLibPackage = null;
         synchronized (mLock) {
             final SharedLibraryInfo latestSharedLibraVersionLPr =
-                    getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage);
+                    getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
             if (latestSharedLibraVersionLPr != null) {
                 sharedLibPackage = mSettings.getPackageLPr(
                         latestSharedLibraVersionLPr.getPackageName());
@@ -13261,18 +13189,18 @@
         cacher.cleanCachedResult(codePath);
     }
 
-    private int[] resolveUserIds(int userId) {
+    int[] resolveUserIds(int userId) {
         return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
-    private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
+    void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             return;
         }
         clearAppDataLeafLIF(pkg, userId, flags);
 
         if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
-            clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+            clearAppProfilesLIF(pkg);
         }
     }
 
@@ -13333,7 +13261,7 @@
         }
     }
 
-    private void clearAppProfilesLIF(AndroidPackage pkg, int userId) {
+    private void clearAppProfilesLIF(AndroidPackage pkg) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
@@ -13673,7 +13601,7 @@
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
                         deletePackageLIF(pkg.getPackageName(), null, true,
                                 mUserManager.getUserIds(), flags, null,
-                                true, null);
+                                true);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                 }
@@ -13697,7 +13625,7 @@
     }
 
     @GuardedBy({"mInstallLock", "mLock"})
-    private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
+    ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
@@ -13709,107 +13637,6 @@
         }
     }
 
-    /** The result of a package scan. */
-    @VisibleForTesting
-    static class ScanResult {
-        /** The request that initiated the scan that produced this result. */
-        public final ScanRequest request;
-        /** Whether or not the package scan was successful */
-        public final boolean success;
-        /**
-         * Whether or not the original PackageSetting needs to be updated with this result on
-         * commit.
-         */
-        public final boolean existingSettingCopied;
-        /**
-         * The final package settings. This may be the same object passed in
-         * the {@link ScanRequest}, but, with modified values.
-         */
-        @Nullable public final PackageSetting pkgSetting;
-        /** ABI code paths that have changed in the package scan */
-        @Nullable public final List<String> changedAbiCodePath;
-
-        public final SharedLibraryInfo staticSharedLibraryInfo;
-
-        public final List<SharedLibraryInfo> dynamicSharedLibraryInfos;
-
-        public ScanResult(
-                ScanRequest request, boolean success,
-                @Nullable PackageSetting pkgSetting,
-                @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
-                SharedLibraryInfo staticSharedLibraryInfo,
-                List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
-            this.request = request;
-            this.success = success;
-            this.pkgSetting = pkgSetting;
-            this.changedAbiCodePath = changedAbiCodePath;
-            this.existingSettingCopied = existingSettingCopied;
-            this.staticSharedLibraryInfo = staticSharedLibraryInfo;
-            this.dynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
-        }
-    }
-
-    /** A package to be scanned */
-    @VisibleForTesting
-    static class ScanRequest {
-        /** The parsed package */
-        @NonNull public final ParsedPackage parsedPackage;
-        /** The package this package replaces */
-        @Nullable public final AndroidPackage oldPkg;
-        /** Shared user settings, if the package has a shared user */
-        @Nullable public final SharedUserSetting sharedUserSetting;
-        /**
-         * Package settings of the currently installed version.
-         * <p><em>IMPORTANT:</em> The contents of this object may be modified
-         * during scan.
-         */
-        @Nullable public final PackageSetting pkgSetting;
-        /** A copy of the settings for the currently installed version */
-        @Nullable public final PackageSetting oldPkgSetting;
-        /** Package settings for the disabled version on the /system partition */
-        @Nullable public final PackageSetting disabledPkgSetting;
-        /** Package settings for the installed version under its original package name */
-        @Nullable public final PackageSetting originalPkgSetting;
-        /** The real package name of a renamed application */
-        @Nullable public final String realPkgName;
-        public final @ParseFlags int parseFlags;
-        public final @ScanFlags int scanFlags;
-        /** The user for which the package is being scanned */
-        @Nullable public final UserHandle user;
-        /** Whether or not the platform package is being scanned */
-        public final boolean isPlatformPackage;
-        /** Override value for package ABI if set during install */
-        @Nullable
-        public final String cpuAbiOverride;
-        public ScanRequest(
-                @NonNull ParsedPackage parsedPackage,
-                @Nullable SharedUserSetting sharedUserSetting,
-                @Nullable AndroidPackage oldPkg,
-                @Nullable PackageSetting pkgSetting,
-                @Nullable PackageSetting disabledPkgSetting,
-                @Nullable PackageSetting originalPkgSetting,
-                @Nullable String realPkgName,
-                @ParseFlags int parseFlags,
-                @ScanFlags int scanFlags,
-                boolean isPlatformPackage,
-                @Nullable UserHandle user,
-                @Nullable String cpuAbiOverride) {
-            this.parsedPackage = parsedPackage;
-            this.oldPkg = oldPkg;
-            this.pkgSetting = pkgSetting;
-            this.sharedUserSetting = sharedUserSetting;
-            this.oldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
-            this.disabledPkgSetting = disabledPkgSetting;
-            this.originalPkgSetting = originalPkgSetting;
-            this.realPkgName = realPkgName;
-            this.parseFlags = parseFlags;
-            this.scanFlags = scanFlags;
-            this.isPlatformPackage = isPlatformPackage;
-            this.user = user;
-            this.cpuAbiOverride = cpuAbiOverride;
-        }
-    }
-
     /**
      * Returns the actual scan flags depending upon the state of the other settings.
      * <p>Updated system applications will not have the following flags set
@@ -13942,7 +13769,7 @@
             } else {
                 isUpdatedSystemApp = disabledPkgSetting != null;
             }
-            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
+            applyPolicy(parsedPackage, scanFlags, mPlatformPackage, isUpdatedSystemApp);
             assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
 
             SharedUserSetting sharedUserSetting = null;
@@ -13969,19 +13796,18 @@
         }
     }
 
-
     /**
      * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering
      * the app ID required for reconcile.
      * @return {@code true} if a new app ID was registered and will need to be cleaned up on
      *         failure.
      */
-    private boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
+    boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
             throws PackageManagerException {
-        if (!result.existingSettingCopied) {
+        if (!result.mExistingSettingCopied || result.mNeedsNewAppId) {
             // THROWS: when we can't allocate a user id. add call to check if there's
             // enough space to ensure we won't throw; otherwise, don't modify state
-            return mSettings.registerAppIdLPw(result.pkgSetting);
+            return mSettings.registerAppIdLPw(result.mPkgSetting, result.mNeedsNewAppId);
         }
         return false;
     }
@@ -13991,11 +13817,11 @@
      * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the
      * referenced method returned true.
      */
-    private void cleanUpAppIdCreation(@NonNull ScanResult result) {
+    void cleanUpAppIdCreation(@NonNull ScanResult result) {
         // iff we've acquired an app ID for a new package setting, remove it so that it can be
         // acquired by another request.
-        if (result.pkgSetting.appId > 0) {
-            mSettings.removeAppIdLPw(result.pkgSetting.appId);
+        if (result.mPkgSetting.appId > 0) {
+            mSettings.removeAppIdLPw(result.mPkgSetting.appId);
         }
     }
 
@@ -14007,37 +13833,37 @@
      * possible and the system is not left in an inconsistent state.
      */
     @GuardedBy({"mLock", "mInstallLock"})
-    private AndroidPackage commitReconciledScanResultLocked(
+    AndroidPackage commitReconciledScanResultLocked(
             @NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
-        final ScanResult result = reconciledPkg.scanResult;
-        final ScanRequest request = result.request;
+        final ScanResult result = reconciledPkg.mScanResult;
+        final ScanRequest request = result.mRequest;
         // TODO(b/135203078): Move this even further away
-        ParsedPackage parsedPackage = request.parsedPackage;
+        ParsedPackage parsedPackage = request.mParsedPackage;
         if ("android".equals(parsedPackage.getPackageName())) {
             // TODO(b/135203078): Move this to initial parse
             parsedPackage.setVersionCode(mSdkVersion)
                     .setVersionCodeMajor(0);
         }
 
-        final AndroidPackage oldPkg = request.oldPkg;
-        final @ParseFlags int parseFlags = request.parseFlags;
-        final @ScanFlags int scanFlags = request.scanFlags;
-        final PackageSetting oldPkgSetting = request.oldPkgSetting;
-        final PackageSetting originalPkgSetting = request.originalPkgSetting;
-        final UserHandle user = request.user;
-        final String realPkgName = request.realPkgName;
-        final List<String> changedAbiCodePath = result.changedAbiCodePath;
+        final AndroidPackage oldPkg = request.mOldPkg;
+        final @ParseFlags int parseFlags = request.mParseFlags;
+        final @ScanFlags int scanFlags = request.mScanFlags;
+        final PackageSetting oldPkgSetting = request.mOldPkgSetting;
+        final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
+        final UserHandle user = request.mUser;
+        final String realPkgName = request.mRealPkgName;
+        final List<String> changedAbiCodePath = result.mChangedAbiCodePath;
         final PackageSetting pkgSetting;
-        if (request.pkgSetting != null && request.pkgSetting.sharedUser != null
-                && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) {
+        if (request.mPkgSetting != null && request.mPkgSetting.sharedUser != null
+                && request.mPkgSetting.sharedUser != result.mPkgSetting.sharedUser) {
             // shared user changed, remove from old shared user
-            request.pkgSetting.sharedUser.removePackage(request.pkgSetting);
+            request.mPkgSetting.sharedUser.removePackage(request.mPkgSetting);
         }
-        if (result.existingSettingCopied) {
-            pkgSetting = request.pkgSetting;
-            pkgSetting.updateFrom(result.pkgSetting);
+        if (result.mExistingSettingCopied) {
+            pkgSetting = request.mPkgSetting;
+            pkgSetting.updateFrom(result.mPkgSetting);
         } else {
-            pkgSetting = result.pkgSetting;
+            pkgSetting = result.mPkgSetting;
             if (originalPkgSetting != null) {
                 mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),
                         originalPkgSetting.name);
@@ -14049,14 +13875,15 @@
         if (pkgSetting.sharedUser != null) {
             pkgSetting.sharedUser.addPackage(pkgSetting);
         }
-        if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) {
+        if (reconciledPkg.mInstallArgs != null
+                && reconciledPkg.mInstallArgs.mForceQueryableOverride) {
             pkgSetting.forceQueryableOverride = true;
         }
 
         // If this is part of a standard install, set the initiating package name, else rely on
         // previous device state.
-        if (reconciledPkg.installArgs != null) {
-            InstallSource installSource = reconciledPkg.installArgs.installSource;
+        if (reconciledPkg.mInstallArgs != null) {
+            InstallSource installSource = reconciledPkg.mInstallArgs.mInstallSource;
             if (installSource.initiatingPackageName != null) {
                 final PackageSetting ips = mSettings.getPackageLPr(
                         installSource.initiatingPackageName);
@@ -14083,20 +13910,20 @@
             mTransferredPackages.add(pkg.getPackageName());
         }
 
-        if (reconciledPkg.collectedSharedLibraryInfos != null) {
+        if (reconciledPkg.mCollectedSharedLibraryInfos != null) {
             executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,
-                    reconciledPkg.collectedSharedLibraryInfos, allUsers);
+                    reconciledPkg.mCollectedSharedLibraryInfos, allUsers);
         }
 
         final KeySetManagerService ksms = mSettings.getKeySetManagerService();
-        if (reconciledPkg.removeAppKeySetData) {
+        if (reconciledPkg.mRemoveAppKeySetData) {
             ksms.removeAppKeySetDataLPw(pkg.getPackageName());
         }
-        if (reconciledPkg.sharedUserSignaturesChanged) {
+        if (reconciledPkg.mSharedUserSignaturesChanged) {
             pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
-            pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails;
+            pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.mSigningDetails;
         }
-        pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
+        pkgSetting.signatures.mSigningDetails = reconciledPkg.mSigningDetails;
 
         if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
             for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
@@ -14285,7 +14112,6 @@
         }
     }
 
-
     /**
      * Just scans the package without any side effects.
      * <p>Not entirely true at the moment. There is still one side effect -- this
@@ -14306,17 +14132,16 @@
             boolean isUnderFactoryTest, long currentTime)
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
-        final UserManagerInternal userManager = injector.getUserManagerInternal();
-        ParsedPackage parsedPackage = request.parsedPackage;
-        PackageSetting pkgSetting = request.pkgSetting;
-        final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
-        final PackageSetting originalPkgSetting = request.originalPkgSetting;
-        final @ParseFlags int parseFlags = request.parseFlags;
-        final @ScanFlags int scanFlags = request.scanFlags;
-        final String realPkgName = request.realPkgName;
-        final SharedUserSetting sharedUserSetting = request.sharedUserSetting;
-        final UserHandle user = request.user;
-        final boolean isPlatformPackage = request.isPlatformPackage;
+        ParsedPackage parsedPackage = request.mParsedPackage;
+        PackageSetting pkgSetting = request.mPkgSetting;
+        final PackageSetting disabledPkgSetting = request.mDisabledPkgSetting;
+        final PackageSetting originalPkgSetting = request.mOriginalPkgSetting;
+        final @ParseFlags int parseFlags = request.mParseFlags;
+        final @ScanFlags int scanFlags = request.mScanFlags;
+        final String realPkgName = request.mRealPkgName;
+        final SharedUserSetting sharedUserSetting = request.mSharedUserSetting;
+        final UserHandle user = request.mUser;
+        final boolean isPlatformPackage = request.mIsPlatformPackage;
 
         List<String> changedAbiCodePath = null;
 
@@ -14352,15 +14177,25 @@
             }
         }
 
+        boolean leavingSharedUser = false;
+
         if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
-            PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Package " + parsedPackage.getPackageName() + " shared user changed from "
-                            + (pkgSetting.sharedUser != null
-                            ? pkgSetting.sharedUser.name : "<nothing>")
-                            + " to "
-                            + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
-                            + "; replacing with new");
-            pkgSetting = null;
+            if (pkgSetting.sharedUser != null && sharedUserSetting == null) {
+                leavingSharedUser = true;
+                // Log that something is leaving shareduid and keep going
+                Slog.i(TAG,
+                        "Package " + parsedPackage.getPackageName() + " shared user changed from "
+                        + pkgSetting.sharedUser.name + " to " + "<nothing>.");
+            } else {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Package " + parsedPackage.getPackageName() + " shared user changed from "
+                                + (pkgSetting.sharedUser != null
+                                ? pkgSetting.sharedUser.name : "<nothing>")
+                                + " to "
+                                + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>")
+                                + "; replacing with new");
+                pkgSetting = null;
+            }
         }
 
         String[] usesStaticLibraries = null;
@@ -14453,7 +14288,7 @@
             configurePackageComponents(parsedPackage);
         }
 
-        final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
+        final String cpuAbiOverride = deriveAbiOverride(request.mCpuAbiOverride);
         final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
 
         final File appLib32InstallDir = getAppLib32InstallDir();
@@ -14636,7 +14471,8 @@
         }
 
         return new ScanResult(request, true, pkgSetting, changedAbiCodePath,
-                !createNewPackage /* existingSettingCopied */, staticSharedLibraryInfo,
+                !createNewPackage /* existingSettingCopied */,
+                leavingSharedUser /* needsNewAppId */, staticSharedLibraryInfo,
                 dynamicSharedLibraryInfos);
     }
 
@@ -14694,7 +14530,7 @@
      * Implementation detail: This method must NOT have any side effect. It would
      * ideally be static, but, it requires locks to read system state.
      */
-    private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
+    private static void applyPolicy(ParsedPackage parsedPackage,
             final @ScanFlags int scanFlags, AndroidPackage platformPkg,
             boolean isUpdatedSystemApp) {
         if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
@@ -14751,14 +14587,6 @@
         PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp);
     }
 
-    private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
-            throws PackageManagerException {
-        if (object == null) {
-            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, message);
-        }
-        return object;
-    }
-
     private <T extends ParsedMainComponent>
             void assertPackageProcesses(AndroidPackage pkg, List<T> components,
             Map<String, ParsedProcess> procs, String compName)
@@ -15143,19 +14971,18 @@
     }
 
     @GuardedBy("mLock")
-    private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
+    private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
         if (nonStaticSharedLibExistsLocked(entry.name)) {
-            return false;
+            return;
         }
 
         SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
-                entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED,
+                entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
                 SharedLibraryInfo.TYPE_BUILTIN,
                 new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
                 entry.isNative);
 
         commitSharedLibraryInfoLocked(libraryInfo);
-        return true;
     }
 
     @GuardedBy("mLock")
@@ -15166,10 +14993,7 @@
     private static boolean sharedLibExists(final String name, final long version,
             Map<String, WatchedLongSparseArray<SharedLibraryInfo>> librarySource) {
         WatchedLongSparseArray<SharedLibraryInfo> versionedLib = librarySource.get(name);
-        if (versionedLib != null && versionedLib.indexOfKey(version) >= 0) {
-            return true;
-        }
-        return false;
+        return versionedLib != null && versionedLib.indexOfKey(version) >= 0;
     }
 
     @GuardedBy("mLock")
@@ -15314,8 +15138,8 @@
         ArrayList<AndroidPackage> clientLibPkgs = null;
         // writer
         synchronized (mLock) {
-            if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
-                for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
+            if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) {
+                for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) {
                     commitSharedLibraryInfoLocked(info);
                 }
                 final Map<String, AndroidPackage> combinedSigningDetails =
@@ -15335,8 +15159,8 @@
                 }
             }
         }
-        if (reconciledPkg.installResult != null) {
-            reconciledPkg.installResult.libraryConsumers = clientLibPkgs;
+        if (reconciledPkg.mInstallResult != null) {
+            reconciledPkg.mInstallResult.mLibraryConsumers = clientLibPkgs;
         }
 
         if ((scanFlags & SCAN_BOOTING) != 0) {
@@ -15380,7 +15204,7 @@
 
             mComponentResolver.addAllComponents(pkg, chatty);
             final boolean isReplace =
-                    reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
+                    reconciledPkg.mPrepareResult != null && reconciledPkg.mPrepareResult.mReplace;
             mAppsFilter.addPackage(pkgSetting, isReplace);
             mPackageProperty.addAllProperties(pkg);
 
@@ -15490,7 +15314,7 @@
         killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
     }
 
-    private void killApplication(String pkgName, @AppIdInt int appId,
+    void killApplication(String pkgName, @AppIdInt int appId,
             @UserIdInt int userId, String reason) {
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
@@ -15509,7 +15333,7 @@
         }
     }
 
-    private void removePackageLI(AndroidPackage pkg, boolean chatty) {
+    void removePackageLI(AndroidPackage pkg, boolean chatty) {
         // Remove the parent package setting
         PackageSetting ps = getPackageSetting(pkg.getPackageName());
         if (ps != null) {
@@ -15615,10 +15439,10 @@
                 } else {
                     resolvedUserIds = userIds;
                 }
-                doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+                doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
                         resolvedUserIds, false, broadcastAllowList, bOptions);
                 if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) {
-                    doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver,
+                    doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver,
                             instantUserIds, true, null, bOptions);
                 }
             } catch (RemoteException ex) {
@@ -15687,7 +15511,7 @@
      * the system and applications allowed to see instant applications to receive package
      * lifecycle events for instant applications.
      */
-    private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras,
+    private void doSendBroadcast(String action, String pkg, Bundle extras,
             int flags, String targetPkg, IIntentReceiver finishedReceiver,
             int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList,
             @Nullable Bundle bOptions) {
@@ -15728,109 +15552,6 @@
         }
     }
 
-    /**
-     * Check if the external storage media is available. This is true if there
-     * is a mounted external storage medium or if the external storage is
-     * emulated.
-     */
-    private boolean isExternalMediaAvailable() {
-        return mMediaMounted || Environment.isExternalStorageEmulated();
-    }
-
-    /**
-     * Ensure that the install reason matches what we know about the package installer (e.g. whether
-     * it is acting on behalf on an enterprise or the user).
-     *
-     * Note that the ordering of the conditionals in this method is important. The checks we perform
-     * are as follows, in this order:
-     *
-     * 1) If the install is being performed by a system app, we can trust the app to have set the
-     *    install reason correctly. Thus, we pass through the install reason unchanged, no matter
-     *    what it is.
-     * 2) If the install is being performed by a device or profile owner app, the install reason
-     *    should be enterprise policy. However, we cannot be sure that the device or profile owner
-     *    set the install reason correctly. If the app targets an older SDK version where install
-     *    reasons did not exist yet, or if the app author simply forgot, the install reason may be
-     *    unset or wrong. Thus, we force the install reason to be enterprise policy.
-     * 3) In all other cases, the install is being performed by a regular app that is neither part
-     *    of the system nor a device or profile owner. We have no reason to believe that this app is
-     *    acting on behalf of the enterprise admin. Thus, we check whether the install reason was
-     *    set to enterprise policy and if so, change it to unknown instead.
-     */
-    private int fixUpInstallReason(String installerPackageName, int installerUid,
-            int installReason) {
-        if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
-                == PERMISSION_GRANTED) {
-            // If the install is being performed by a system app, we trust that app to have set the
-            // install reason correctly.
-            return installReason;
-        }
-        final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(
-                UserHandle.getUserId(installerUid));
-        if (ownerPackage != null && ownerPackage.equals(installerPackageName)) {
-            // If the install is being performed by a device or profile owner, the install
-            // reason should be enterprise policy.
-            return PackageManager.INSTALL_REASON_POLICY;
-        }
-
-
-        if (installReason == PackageManager.INSTALL_REASON_POLICY) {
-            // If the install is being performed by a regular app (i.e. neither system app nor
-            // device or profile owner), we have no reason to believe that the app is acting on
-            // behalf of an enterprise. If the app set the install reason to enterprise policy,
-            // change it to unknown instead.
-            return PackageManager.INSTALL_REASON_UNKNOWN;
-        }
-
-        // If the install is being performed by a regular app and the install reason was set to any
-        // value but enterprise policy, leave the install reason unchanged.
-        return installReason;
-    }
-
-    void installStage(InstallParams params) {
-        final Message msg = mHandler.obtainMessage(INIT_COPY);
-        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
-        msg.obj = params;
-
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
-                System.identityHashCode(msg.obj));
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                System.identityHashCode(msg.obj));
-
-        mHandler.sendMessage(msg);
-    }
-
-    void installStage(InstallParams parent, List<InstallParams> children)
-            throws PackageManagerException {
-        final Message msg = mHandler.obtainMessage(INIT_COPY);
-        final MultiPackageInstallParams params =
-                new MultiPackageInstallParams(parent, children);
-        params.setTraceMethod("installStageMultiPackage")
-                .setTraceCookie(System.identityHashCode(params));
-        msg.obj = params;
-
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
-                System.identityHashCode(msg.obj));
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                System.identityHashCode(msg.obj));
-        mHandler.sendMessage(msg);
-    }
-
-    void verifyStage(VerificationParams params) {
-        mHandler.post(()-> {
-            params.startCopy();
-        });
-    }
-
-    void verifyStage(VerificationParams parent, List<VerificationParams> children)
-            throws PackageManagerException {
-        final MultiPackageVerificationParams params =
-                new MultiPackageVerificationParams(parent, children);
-        mHandler.post(()-> {
-            params.startCopy();
-        });
-    }
-
     private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
             int userId, int dataLoaderType) {
         final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -16075,11 +15796,11 @@
     private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
             int userId) {
         final PackageRemovedInfo info = new PackageRemovedInfo(this);
-        info.removedPackage = packageName;
-        info.installerPackageName = pkgSetting.installSource.installerPackageName;
-        info.removedUsers = new int[] {userId};
-        info.broadcastUsers = new int[] {userId};
-        info.uid = UserHandle.getUid(userId, pkgSetting.appId);
+        info.mRemovedPackage = packageName;
+        info.mInstallerPackageName = pkgSetting.installSource.installerPackageName;
+        info.mRemovedUsers = new int[] {userId};
+        info.mBroadcastUsers = new int[] {userId};
+        info.mUid = UserHandle.getUid(userId, pkgSetting.appId);
         info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/);
     }
 
@@ -16279,17 +16000,17 @@
                     updateSequenceNumberLP(pkgSetting, new int[]{ userId });
                 }
                 // start async restore with no post-install since we finish install here
-                PackageInstalledInfo res =
-                        createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
-                res.pkg = pkgSetting.pkg;
-                res.newUsers = new int[]{ userId };
+                PackageInstalledInfo res = new PackageInstalledInfo(
+                        PackageManager.INSTALL_SUCCEEDED);
+                res.mPkg = pkgSetting.pkg;
+                res.mNewUsers = new int[]{ userId };
 
                 PostInstallData postInstallData =
                         new PostInstallData(null, res, () -> {
                             restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                                    pkgSetting.getInstallReason(userId), userId);
+                                    userId);
                             if (intentSender != null) {
-                                onRestoreComplete(res.returnCode, mContext, intentSender);
+                                onRestoreComplete(res.mReturnCode, mContext, intentSender);
                             }
                         });
                 restoreAndPostInstall(userId, res, postInstallData);
@@ -16564,7 +16285,7 @@
                 } else {
                     intentExtras = null;
                 }
-                doSendBroadcast(am, action, null, intentExtras,
+                doSendBroadcast(action, null, intentExtras,
                         Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
                         targetUserIds, false, null, null);
             }
@@ -16864,7 +16585,7 @@
         }
     }
 
-    private void broadcastPackageVerified(int verificationId, Uri packageUri,
+    void broadcastPackageVerified(int verificationId, Uri packageUri,
             int verificationCode, @Nullable String rootHashString, int dataLoaderType,
             UserHandle user) {
         final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
@@ -16881,101 +16602,6 @@
                 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
     }
 
-    private ComponentName matchComponentForVerifier(String packageName,
-            List<ResolveInfo> receivers) {
-        ActivityInfo targetReceiver = null;
-
-        final int NR = receivers.size();
-        for (int i = 0; i < NR; i++) {
-            final ResolveInfo info = receivers.get(i);
-            if (info.activityInfo == null) {
-                continue;
-            }
-
-            if (packageName.equals(info.activityInfo.packageName)) {
-                targetReceiver = info.activityInfo;
-                break;
-            }
-        }
-
-        if (targetReceiver == null) {
-            return null;
-        }
-
-        return new ComponentName(targetReceiver.packageName, targetReceiver.name);
-    }
-
-    private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
-            List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
-        if (pkgInfo.verifiers.length == 0) {
-            return null;
-        }
-
-        final int N = pkgInfo.verifiers.length;
-        final List<ComponentName> sufficientVerifiers = new ArrayList<>(N + 1);
-        for (int i = 0; i < N; i++) {
-            final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
-
-            final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
-                    receivers);
-            if (comp == null) {
-                continue;
-            }
-
-            final int verifierUid = getUidForVerifier(verifierInfo);
-            if (verifierUid == -1) {
-                continue;
-            }
-
-            if (DEBUG_VERIFY) {
-                Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
-                        + " with the correct signature");
-            }
-            sufficientVerifiers.add(comp);
-            verificationState.addSufficientVerifier(verifierUid);
-        }
-
-        return sufficientVerifiers;
-    }
-
-    private int getUidForVerifier(VerifierInfo verifierInfo) {
-        synchronized (mLock) {
-            final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
-            if (pkg == null) {
-                return -1;
-            } else if (pkg.getSigningDetails().getSignatures().length != 1) {
-                Slog.i(TAG, "Verifier package " + verifierInfo.packageName
-                        + " has more than one signature; ignoring");
-                return -1;
-            }
-
-            /*
-             * If the public key of the package's signature does not match
-             * our expected public key, then this is a different package and
-             * we should skip.
-             */
-
-            final byte[] expectedPublicKey;
-            try {
-                final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
-                final PublicKey publicKey = verifierSig.getPublicKey();
-                expectedPublicKey = publicKey.getEncoded();
-            } catch (CertificateException e) {
-                return -1;
-            }
-
-            final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
-
-            if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
-                Slog.i(TAG, "Verifier package " + verifierInfo.packageName
-                        + " does not have the expected public key; ignoring");
-                return -1;
-            }
-
-            return pkg.getUid();
-        }
-    }
-
     private void setEnableRollbackCode(int token, int enableRollbackCode) {
         final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
         msg.arg1 = token;
@@ -17002,7 +16628,7 @@
      *
      * @return verification timeout in milliseconds
      */
-    private long getVerificationTimeout() {
+    long getVerificationTimeout() {
         long timeout = Global.getLong(mContext.getContentResolver(),
                 Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT);
         // The setting can be used to increase the timeout but not decrease it, since that is
@@ -17010,18 +16636,6 @@
         return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT);
     }
 
-    /**
-     * Get the integrity verification timeout.
-     *
-     * @return verification timeout in milliseconds
-     */
-    private long getIntegrityVerificationTimeout() {
-        long timeout = Global.getLong(mContext.getContentResolver(),
-                Global.APP_INTEGRITY_VERIFICATION_TIMEOUT, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
-        // The setting can be used to increase the timeout but not decrease it, since that is
-        // equivalent to disabling the integrity component.
-        return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
-    }
 
     /**
      * Get the default verification agent response code.
@@ -17046,65 +16660,6 @@
         return PackageManager.VERIFICATION_REJECT;
     }
 
-    /**
-     * Check whether or not package verification has been enabled.
-     *
-     * @return true if verification should be performed
-     */
-    private boolean isVerificationEnabled(
-            PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
-        if (!DEFAULT_VERIFY_ENABLE) {
-            return false;
-        }
-
-        // Check if installing from ADB
-        if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
-            if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
-                return true;
-            }
-            // Check if the developer wants to skip verification for ADB installs
-            if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
-                synchronized (mLock) {
-                    if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
-                        // Always verify fresh install
-                        return true;
-                    }
-                }
-                // Only skip when apk is debuggable
-                return !pkgInfoLite.debuggable;
-            }
-            return Global.getInt(mContext.getContentResolver(),
-                    Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
-        }
-
-        // only when not installed from ADB, skip verification for instant apps when
-        // the installer and verifier are the same.
-        if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-            if (mInstantAppInstallerActivity != null
-                    && mInstantAppInstallerActivity.packageName.equals(
-                            mRequiredVerifierPackage)) {
-                try {
-                    mInjector.getSystemService(AppOpsManager.class)
-                            .checkPackage(installerUid, mRequiredVerifierPackage);
-                    if (DEBUG_VERIFY) {
-                        Slog.i(TAG, "disable verification for instant app");
-                    }
-                    return false;
-                } catch (SecurityException ignore) { }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check whether or not integrity verification has been enabled.
-     */
-    private boolean isIntegrityVerificationEnabled() {
-        // We are not exposing this as a user-configurable setting because we don't want to provide
-        // an easy way to get around the integrity check.
-        return DEFAULT_INTEGRITY_VERIFY_ENABLE;
-    }
-
     @Deprecated
     @Override
     public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
@@ -17317,124 +16872,18 @@
         }
     }
 
-    // Queue up an async operation since the package installation may take a little while.
-    private void processInstallRequestsAsync(boolean success,
-            List<InstallRequest> installRequests) {
-        mHandler.post(() -> {
-            List<InstallRequest> apexInstallRequests = new ArrayList<>();
-            List<InstallRequest> apkInstallRequests = new ArrayList<>();
-            for (InstallRequest request : installRequests) {
-                if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                    apexInstallRequests.add(request);
-                } else {
-                    apkInstallRequests.add(request);
-                }
-            }
-            // Note: supporting multi package install of both APEXes and APKs might requir some
-            // thinking to ensure atomicity of the install.
-            if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
-                // This should've been caught at the validation step, but for some reason wasn't.
-                throw new IllegalStateException(
-                        "Attempted to do a multi package install of both APEXes and APKs");
-            }
-            if (!apexInstallRequests.isEmpty()) {
-                if (success) {
-                    // Since installApexPackages requires talking to external service (apexd), we
-                    // schedule to run it async. Once it finishes, it will resume the install.
-                    Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
-                            "installApexPackages");
-                    t.start();
-                } else {
-                    // Non-staged APEX installation failed somewhere before
-                    // processInstallRequestAsync. In that case just notify the observer about the
-                    // failure.
-                    InstallRequest request = apexInstallRequests.get(0);
-                    notifyInstallObserver(request.installResult, request.args.observer);
-                }
-                return;
-            }
-            if (success) {
-                for (InstallRequest request : apkInstallRequests) {
-                    request.args.doPreInstall(request.installResult.returnCode);
-                }
-                synchronized (mInstallLock) {
-                    installPackagesTracedLI(apkInstallRequests);
-                }
-                for (InstallRequest request : apkInstallRequests) {
-                    request.args.doPostInstall(
-                            request.installResult.returnCode, request.installResult.uid);
-                }
-            }
-            for (InstallRequest request : apkInstallRequests) {
-                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
-                        new PostInstallData(request.args, request.installResult, null));
-            }
-        });
-    }
-
-    private void installApexPackagesTraced(List<InstallRequest> requests) {
-        try {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages");
-            installApexPackages(requests);
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
-
-    private void installApexPackages(List<InstallRequest> requests) {
-        if (requests.isEmpty()) {
-            return;
-        }
-        if (requests.size() != 1) {
-            throw new IllegalStateException(
-                "Only a non-staged install of a single APEX is supported");
-        }
-        InstallRequest request = requests.get(0);
-        try {
-            // Should directory scanning logic be moved to ApexManager for better test coverage?
-            final File dir = request.args.origin.resolvedFile;
-            final File[] apexes = dir.listFiles();
-            if (apexes == null) {
-                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                        dir.getAbsolutePath() + " is not a directory");
-            }
-            if (apexes.length != 1) {
-                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                        "Expected exactly one .apex file under " + dir.getAbsolutePath()
-                                + " got: " + apexes.length);
-            }
-            try (PackageParser2 packageParser = mInjector.getScanningPackageParser()) {
-                mApexManager.installPackage(apexes[0], packageParser);
-            }
-        } catch (PackageManagerException e) {
-            request.installResult.setError("APEX installation failed", e);
-        }
-        invalidatePackageInfoCache();
-        notifyInstallObserver(request.installResult, request.args.observer);
-    }
-
-    private PackageInstalledInfo createPackageInstalledInfo(
-            int currentStatus) {
-        PackageInstalledInfo res = new PackageInstalledInfo();
-        res.setReturnCode(currentStatus);
-        res.uid = -1;
-        res.pkg = null;
-        res.removedInfo = null;
-        return res;
-    }
-
     /** @param data Post-install is performed only if this is non-null. */
-    private void restoreAndPostInstall(
+    void restoreAndPostInstall(
             int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
         if (DEBUG_INSTALL) {
-            Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
+            Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.mPkg);
         }
 
         // A restore should be requested at this point if (a) the install
         // succeeded, (b) the operation is not an update.
-        final boolean update = res.removedInfo != null
-                && res.removedInfo.removedPackage != null;
-        boolean doRestore = !update && res.pkg != null;
+        final boolean update = res.mRemovedInfo != null
+                && res.mRemovedInfo.mRemovedPackage != null;
+        boolean doRestore = !update && res.mPkg != null;
 
         // Set up the post-install work request bookkeeping.  This will be used
         // and cleaned up by the post-install event handling regardless of whether
@@ -17450,13 +16899,13 @@
 
         if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
 
-        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+        if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
             // Pass responsibility to the Backup Manager.  It will perform a
             // restore if appropriate, then pass responsibility back to the
             // Package Manager to run the post-install observer callbacks
             // and broadcasts.
-            if (res.freezer != null) {
-                res.freezer.close();
+            if (res.mFreezer != null) {
+                res.mFreezer.close();
             }
             doRestore = performBackupManagerRestore(userId, token, res);
         }
@@ -17466,7 +16915,7 @@
         // need to be snapshotted or restored for the package.
         //
         // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
-        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+        if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
             doRestore = performRollbackManagerRestore(userId, token, res, data);
         }
 
@@ -17502,7 +16951,7 @@
             try {
                 if (bm.isUserReadyForBackup(userId)) {
                     bm.restoreAtInstallForUser(
-                            userId, res.pkg.getPackageName(), token);
+                            userId, res.mPkg.getPackageName(), token);
                 } else {
                     Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
                             + "didn't take place.");
@@ -17529,7 +16978,7 @@
             PostInstallData data) {
         RollbackManagerInternal rm = mInjector.getLocalService(RollbackManagerInternal.class);
 
-        final String packageName = res.pkg.getPackageName();
+        final String packageName = res.mPkg.getPackageName();
         final int[] allUsers = mUserManager.getUserIds();
         final int[] installedUsers;
 
@@ -17549,11 +16998,11 @@
         }
 
         boolean doSnapshotOrRestore = data != null && data.args != null
-                && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
-                || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
+                && ((data.args.mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0
+                || (data.args.mInstallFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
 
         if (ps != null && doSnapshotOrRestore) {
-            final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps);
+            final String seInfo = AndroidPackageUtils.getSeInfo(res.mPkg, ps);
             rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers),
                     appId, ceDataInode, seInfo, token);
             return true;
@@ -17581,13 +17030,13 @@
         mHandler.post(() -> {
             for (int i = 0; i < mRunningInstalls.size(); i++) {
                 final PostInstallData data = mRunningInstalls.valueAt(i);
-                if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+                if (data.res.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
                     continue;
                 }
-                if (packageName.equals(data.res.pkg.getPackageName())) {
+                if (packageName.equals(data.res.mPkg.getPackageName())) {
                     // right package; but is it for the right user?
-                    for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
-                        if (userId == data.res.newUsers[uIndex]) {
+                    for (int uIndex = 0; uIndex < data.res.mNewUsers.length; uIndex++) {
+                        if (userId == data.res.mNewUsers[uIndex]) {
                             if (DEBUG_BACKUP) {
                                 Slog.i(TAG, "Package " + packageName
                                         + " being restored so deferring FIRST_LAUNCH");
@@ -17614,1388 +17063,12 @@
                 installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null);
     }
 
-    private abstract class HandlerParams {
-        /** User handle for the user requesting the information or installation. */
-        private final UserHandle mUser;
-        String traceMethod;
-        int traceCookie;
-
-        HandlerParams(UserHandle user) {
-            mUser = user;
-        }
-
-        UserHandle getUser() {
-            return mUser;
-        }
-
-        HandlerParams setTraceMethod(String traceMethod) {
-            this.traceMethod = traceMethod;
-            return this;
-        }
-
-        HandlerParams setTraceCookie(int traceCookie) {
-            this.traceCookie = traceCookie;
-            return this;
-        }
-
-        final void startCopy() {
-            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-            handleStartCopy();
-            handleReturnCode();
-        }
-
-        abstract void handleStartCopy();
-        abstract void handleReturnCode();
-    }
-
-    static class OriginInfo {
-        /**
-         * Location where install is coming from, before it has been
-         * copied/renamed into place. This could be a single monolithic APK
-         * file, or a cluster directory. This location may be untrusted.
-         */
-        final File file;
-
-        /**
-         * Flag indicating that {@link #file} has already been staged, meaning downstream users
-         * don't need to defensively copy the contents.
-         */
-        final boolean staged;
-
-        /**
-         * Flag indicating that {@link #file} is an already installed app that is being moved.
-         */
-        final boolean existing;
-
-        final String resolvedPath;
-        final File resolvedFile;
-
-        static OriginInfo fromNothing() {
-            return new OriginInfo(null, false, false);
-        }
-
-        static OriginInfo fromUntrustedFile(File file) {
-            return new OriginInfo(file, false, false);
-        }
-
-        static OriginInfo fromExistingFile(File file) {
-            return new OriginInfo(file, false, true);
-        }
-
-        static OriginInfo fromStagedFile(File file) {
-            return new OriginInfo(file, true, false);
-        }
-
-        private OriginInfo(File file, boolean staged, boolean existing) {
-            this.file = file;
-            this.staged = staged;
-            this.existing = existing;
-
-            if (file != null) {
-                resolvedPath = file.getAbsolutePath();
-                resolvedFile = file;
-            } else {
-                resolvedPath = null;
-                resolvedFile = null;
-            }
-        }
-    }
-
-    static class MoveInfo {
-        final int moveId;
-        final String fromUuid;
-        final String toUuid;
-        final String packageName;
-        final int appId;
-        final String seinfo;
-        final int targetSdkVersion;
-        final String fromCodePath;
-
-        public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
-                int appId, String seinfo, int targetSdkVersion,
-                String fromCodePath) {
-            this.moveId = moveId;
-            this.fromUuid = fromUuid;
-            this.toUuid = toUuid;
-            this.packageName = packageName;
-            this.appId = appId;
-            this.seinfo = seinfo;
-            this.targetSdkVersion = targetSdkVersion;
-            this.fromCodePath = fromCodePath;
-        }
-    }
-
-    static class VerificationInfo {
-        /** A constant used to indicate that a uid value is not present. */
-        public static final int NO_UID = -1;
-
-        /** URI referencing where the package was downloaded from. */
-        final Uri originatingUri;
-
-        /** HTTP referrer URI associated with the originatingURI. */
-        final Uri referrer;
-
-        /** UID of the application that the install request originated from. */
-        final int originatingUid;
-
-        /** UID of application requesting the install */
-        final int installerUid;
-
-        VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
-            this.originatingUri = originatingUri;
-            this.referrer = referrer;
-            this.originatingUid = originatingUid;
-            this.installerUid = installerUid;
-        }
-    }
-
-    /**
-     * Container for a multi-package install which refers to all install sessions and args being
-     * committed together.
-     */
-    class MultiPackageInstallParams extends HandlerParams {
-        private final List<InstallParams> mChildParams;
-        private final Map<InstallArgs, Integer> mCurrentState;
-
-        MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
-                throws PackageManagerException {
-            super(parent.getUser());
-            if (childParams.size() == 0) {
-                throw new PackageManagerException("No child sessions found!");
-            }
-            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());
-        }
-
-        @Override
-        void handleStartCopy() {
-            for (InstallParams params : mChildParams) {
-                params.handleStartCopy();
-            }
-        }
-
-        @Override
-        void handleReturnCode() {
-            for (InstallParams params : mChildParams) {
-                params.handleReturnCode();
-            }
-        }
-
-        void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
-            mCurrentState.put(args, currentStatus);
-            if (mCurrentState.size() != mChildParams.size()) {
-                return;
-            }
-            int completeStatus = PackageManager.INSTALL_SUCCEEDED;
-            for (Integer status : mCurrentState.values()) {
-                if (status == PackageManager.INSTALL_UNKNOWN) {
-                    return;
-                } else if (status != PackageManager.INSTALL_SUCCEEDED) {
-                    completeStatus = status;
-                    break;
-                }
-            }
-            final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
-            for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
-                installRequests.add(new InstallRequest(entry.getKey(),
-                        createPackageInstalledInfo(completeStatus)));
-            }
-            processInstallRequestsAsync(
-                    completeStatus == PackageManager.INSTALL_SUCCEEDED,
-                    installRequests);
-        }
-    }
-
-    class InstallParams extends HandlerParams {
-        final OriginInfo origin;
-        final MoveInfo move;
-        final IPackageInstallObserver2 observer;
-        int installFlags;
-        @NonNull final InstallSource installSource;
-        final String volumeUuid;
-        int mRet;
-        final String packageAbiOverride;
-        final String[] grantedRuntimePermissions;
-        final List<String> whitelistedRestrictedPermissions;
-        final int autoRevokePermissionsMode;
-        final SigningDetails signingDetails;
-        final int installReason;
-        final int mInstallScenario;
-        @Nullable MultiPackageInstallParams mParentInstallParams;
-        final boolean forceQueryableOverride;
-        final int mDataLoaderType;
-        final long requiredInstalledVersionCode;
-        final PackageLite mPackageLite;
-
-        InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
-                int installFlags, InstallSource installSource, String volumeUuid,
-                UserHandle user, String packageAbiOverride, PackageLite packageLite) {
-            super(user);
-            this.origin = origin;
-            this.move = move;
-            this.observer = observer;
-            this.installFlags = installFlags;
-            this.installSource = Preconditions.checkNotNull(installSource);
-            this.volumeUuid = volumeUuid;
-            this.packageAbiOverride = packageAbiOverride;
-
-            this.grantedRuntimePermissions = null;
-            this.whitelistedRestrictedPermissions = null;
-            this.autoRevokePermissionsMode = MODE_DEFAULT;
-            this.signingDetails = SigningDetails.UNKNOWN;
-            this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
-            this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
-            this.forceQueryableOverride = false;
-            this.mDataLoaderType = DataLoaderType.NONE;
-            this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
-            this.mPackageLite = packageLite;
-        }
-
-        InstallParams(File stagedDir, IPackageInstallObserver2 observer,
-                PackageInstaller.SessionParams sessionParams, InstallSource installSource,
-                UserHandle user, SigningDetails signingDetails, int installerUid,
-                PackageLite packageLite) {
-            super(user);
-            origin = OriginInfo.fromStagedFile(stagedDir);
-            move = null;
-            installReason = fixUpInstallReason(
-                    installSource.installerPackageName, installerUid, sessionParams.installReason);
-            mInstallScenario = sessionParams.installScenario;
-            this.observer = observer;
-            installFlags = sessionParams.installFlags;
-            this.installSource = installSource;
-            volumeUuid = sessionParams.volumeUuid;
-            packageAbiOverride = sessionParams.abiOverride;
-            grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
-            whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
-            autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
-            this.signingDetails = signingDetails;
-            forceQueryableOverride = sessionParams.forceQueryableOverride;
-            mDataLoaderType = (sessionParams.dataLoaderParams != null)
-                    ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
-            requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
-            mPackageLite = packageLite;
-        }
-
-        @Override
-        public String toString() {
-            return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
-                    + " file=" + origin.file + "}";
-        }
-
-        private int installLocationPolicy(PackageInfoLite pkgLite) {
-            String packageName = pkgLite.packageName;
-            int installLocation = pkgLite.installLocation;
-            // reader
-            synchronized (mLock) {
-                // Currently installed package which the new package is attempting to replace or
-                // null if no such package is installed.
-                AndroidPackage installedPkg = mPackages.get(packageName);
-
-                if (installedPkg != null) {
-                    if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
-                        // Check for updated system application.
-                        if (installedPkg.isSystem()) {
-                            return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-                        } else {
-                            // If current upgrade specifies particular preference
-                            if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
-                                // Application explicitly specified internal.
-                                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-                            } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
-                                // App explictly prefers external. Let policy decide
-                            } else {
-                                // Prefer previous location
-                                if (installedPkg.isExternalStorage()) {
-                                    return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
-                                }
-                                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-                            }
-                        }
-                    } else {
-                        // Invalid install. Return error code
-                        return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS;
-                    }
-                }
-            }
-            return pkgLite.recommendedInstallLocation;
-        }
-
-        /**
-         * Override install location based on default policy if needed.
-         *
-         * Only {@link #installFlags} may mutate in this method.
-         *
-         * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in
-         * {@link #installFlags}
-         */
-        private int overrideInstallLocation(PackageInfoLite pkgLite) {
-            final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-            if (DEBUG_INSTANT && ephemeral) {
-                Slog.v(TAG, "pkgLite for install: " + pkgLite);
-            }
-
-            if (origin.staged) {
-                // If we're already staged, we've firmly committed to an install location
-                if (origin.file != null) {
-                    installFlags |= PackageManager.INSTALL_INTERNAL;
-                } else {
-                    throw new IllegalStateException("Invalid stage location");
-                }
-            } else if (pkgLite.recommendedInstallLocation
-                    == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
-                /*
-                 * If we are not staged and have too little free space, try to free cache
-                 * before giving up.
-                 */
-                // TODO: focus freeing disk space on the target device
-                final StorageManager storage = StorageManager.from(mContext);
-                final long lowThreshold = storage.getStorageLowBytes(
-                        Environment.getDataDirectory());
-
-                final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
-                        origin.resolvedPath, packageAbiOverride);
-                if (sizeBytes >= 0) {
-                    try {
-                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
-                        pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                                mPackageLite, origin.resolvedPath, installFlags,
-                                packageAbiOverride);
-                    } catch (InstallerException e) {
-                        Slog.w(TAG, "Failed to free cache", e);
-                    }
-                }
-
-                /*
-                 * The cache free must have deleted the file we downloaded to install.
-                 *
-                 * TODO: fix the "freeCache" call to not delete the file we care about.
-                 */
-                if (pkgLite.recommendedInstallLocation
-                        == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
-                    pkgLite.recommendedInstallLocation
-                            = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
-                }
-            }
-
-            int ret = INSTALL_SUCCEEDED;
-            int loc = pkgLite.recommendedInstallLocation;
-            if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
-                ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
-            } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
-                ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
-            } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
-                ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
-                ret = PackageManager.INSTALL_FAILED_INVALID_APK;
-            } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
-                ret = PackageManager.INSTALL_FAILED_INVALID_URI;
-            } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
-                ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
-            } else {
-                // Override with defaults if needed.
-                loc = installLocationPolicy(pkgLite);
-
-                final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
-
-                if (!onInt) {
-                    // Override install location with flags
-                    if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
-                        // Set the flag to install on external media.
-                        installFlags &= ~PackageManager.INSTALL_INTERNAL;
-                    } else {
-                        // Make sure the flag for installing on external
-                        // media is unset
-                        installFlags |= PackageManager.INSTALL_INTERNAL;
-                    }
-                }
-            }
-            return ret;
-        }
-
-        /*
-         * Invoke remote method to get package information and install
-         * location values. Override install location based on default
-         * policy if needed and then create install arguments based
-         * on the install location.
-         */
-        public void handleStartCopy() {
-            if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
-                mRet = INSTALL_SUCCEEDED;
-                return;
-            }
-            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
-
-            // For staged session, there is a delay between its verification and install. Device
-            // state can change within this delay and hence we need to re-verify certain conditions.
-            boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
-            if (isStaged) {
-                Pair<Integer, String> ret = verifyReplacingVersionCode(
-                        pkgLite, requiredInstalledVersionCode, installFlags);
-                mRet = ret.first;
-                if (mRet != INSTALL_SUCCEEDED) {
-                    return;
-                }
-            }
-
-            mRet = overrideInstallLocation(pkgLite);
-        }
-
-        @Override
-        void handleReturnCode() {
-            processPendingInstall();
-        }
-
-        private void processPendingInstall() {
-            InstallArgs args = createInstallArgs(this);
-            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
-                mRet = args.copyApk();
-            }
-            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
-                F2fsUtils.releaseCompressedBlocks(
-                        mContext.getContentResolver(), new File(args.getCodePath()));
-            }
-            if (mParentInstallParams != null) {
-                mParentInstallParams.tryProcessInstallRequest(args, mRet);
-            } else {
-                PackageInstalledInfo res = createPackageInstalledInfo(mRet);
-                processInstallRequestsAsync(
-                        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
-                        Collections.singletonList(new InstallRequest(args, res)));
-            }
-        }
-    }
-
-    /**
-     * Container for a multi-package install which refers to all install sessions and args being
-     * committed together.
-     */
-    class MultiPackageVerificationParams extends HandlerParams {
-        private final IPackageInstallObserver2 mObserver;
-        private final List<VerificationParams> mChildParams;
-        private final Map<VerificationParams, Integer> mVerificationState;
-
-        MultiPackageVerificationParams(
-                VerificationParams parent,
-                List<VerificationParams> children)
-                throws PackageManagerException {
-            super(parent.getUser());
-            if (children.size() == 0) {
-                throw new PackageManagerException("No child sessions found!");
-            }
-            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.mVerificationState = new ArrayMap<>(mChildParams.size());
-            mObserver = parent.observer;
-        }
-
-        @Override
-        void handleStartCopy() {
-            for (VerificationParams params : mChildParams) {
-                params.handleStartCopy();
-            }
-        }
-
-        @Override
-        void handleReturnCode() {
-            for (VerificationParams params : mChildParams) {
-                params.handleReturnCode();
-            }
-        }
-
-        void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
-            mVerificationState.put(child, currentStatus);
-            if (mVerificationState.size() != mChildParams.size()) {
-                return;
-            }
-            int completeStatus = PackageManager.INSTALL_SUCCEEDED;
-            String errorMsg = null;
-            for (VerificationParams params : mVerificationState.keySet()) {
-                int status = params.mRet;
-                if (status == PackageManager.INSTALL_UNKNOWN) {
-                    return;
-                } else if (status != PackageManager.INSTALL_SUCCEEDED) {
-                    completeStatus = status;
-                    errorMsg = params.mErrorMessage;
-                    break;
-                }
-            }
-            try {
-                mObserver.onPackageInstalled(null, completeStatus,
-                        errorMsg, new Bundle());
-            } catch (RemoteException e) {
-                Slog.i(TAG, "Observer no longer exists.");
-            }
-        }
-    }
-
-    class VerificationParams extends HandlerParams {
-        final OriginInfo origin;
-        final IPackageInstallObserver2 observer;
-        final int installFlags;
-        @NonNull final InstallSource installSource;
-        final String packageAbiOverride;
-        final VerificationInfo verificationInfo;
-        final SigningDetails signingDetails;
-        @Nullable MultiPackageVerificationParams mParentVerificationParams;
-        final long requiredInstalledVersionCode;
-        final int mDataLoaderType;
-        final int mSessionId;
-
-        private boolean mWaitForVerificationToComplete;
-        private boolean mWaitForIntegrityVerificationToComplete;
-        private boolean mWaitForEnableRollbackToComplete;
-        private int mRet = PackageManager.INSTALL_SUCCEEDED;
-        private String mErrorMessage = null;
-
-        final PackageLite mPackageLite;
-
-        VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
-                PackageInstaller.SessionParams sessionParams, InstallSource installSource,
-                int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite) {
-            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,
-                    installerUid
-            );
-            this.signingDetails = signingDetails;
-            requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
-            mDataLoaderType = (sessionParams.dataLoaderParams != null)
-                    ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
-            mSessionId = sessionId;
-            mPackageLite = lite;
-        }
-
-        @Override
-        public String toString() {
-            return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
-                    + " file=" + origin.file + "}";
-        }
-
-        public void handleStartCopy() {
-            PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
-
-            Pair<Integer, String> ret = verifyReplacingVersionCode(
-                    pkgLite, requiredInstalledVersionCode, installFlags);
-            setReturnCode(ret.first, ret.second);
-            if (mRet != INSTALL_SUCCEEDED) {
-                return;
-            }
-
-            // Perform package verification and enable rollback (unless we are simply moving the
-            // package).
-            if (!origin.existing) {
-                if ((installFlags & PackageManager.INSTALL_APEX) == 0) {
-                    // TODO(b/182426975): treat APEX as APK when APK verification is concerned
-                    sendApkVerificationRequest(pkgLite);
-                }
-                if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
-                    sendEnableRollbackRequest();
-                }
-            }
-        }
-
-        void sendApkVerificationRequest(PackageInfoLite pkgLite) {
-            final int verificationId = mPendingVerificationToken++;
-
-            PackageVerificationState verificationState =
-                    new PackageVerificationState(this);
-            mPendingVerification.append(verificationId, verificationState);
-
-            sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
-            sendPackageVerificationRequest(
-                    verificationId, pkgLite, verificationState);
-
-            // If both verifications are skipped, we should remove the state.
-            if (verificationState.areAllVerificationsComplete()) {
-                mPendingVerification.remove(verificationId);
-            }
-        }
-
-        void sendEnableRollbackRequest() {
-            final int enableRollbackToken = mPendingEnableRollbackToken++;
-            Trace.asyncTraceBegin(
-                    TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
-            mPendingEnableRollback.append(enableRollbackToken, this);
-
-            Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
-            enableRollbackIntent.putExtra(
-                    PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
-                    enableRollbackToken);
-            enableRollbackIntent.putExtra(
-                    PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
-                    mSessionId);
-            enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
-            enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-            // Allow the broadcast to be sent before boot complete.
-            // This is needed when committing the apk part of a staged
-            // session in early boot. The rollback manager registers
-            // its receiver early enough during the boot process that
-            // it will not miss the broadcast.
-            enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
-            mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
-                    android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
-
-            mWaitForEnableRollbackToComplete = true;
-
-            // the duration to wait for rollback to be enabled, in millis
-            long rollbackTimeout = DeviceConfig.getLong(
-                    DeviceConfig.NAMESPACE_ROLLBACK,
-                    PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
-                    DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
-            if (rollbackTimeout < 0) {
-                rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
-            }
-            final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
-            msg.arg1 = enableRollbackToken;
-            msg.arg2 = mSessionId;
-            mHandler.sendMessageDelayed(msg, rollbackTimeout);
-        }
-
-        /**
-         * Send a request to check the integrity of the package.
-         */
-        void sendIntegrityVerificationRequest(
-                int verificationId,
-                PackageInfoLite pkgLite,
-                PackageVerificationState verificationState) {
-            if (!isIntegrityVerificationEnabled()) {
-                // Consider the integrity check as passed.
-                verificationState.setIntegrityVerificationResult(
-                        PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-                return;
-            }
-
-            final Intent integrityVerification =
-                    new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-
-            integrityVerification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
-                    PACKAGE_MIME_TYPE);
-
-            final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
-                    | Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                    | Intent.FLAG_RECEIVER_FOREGROUND;
-            integrityVerification.addFlags(flags);
-
-            integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
-            integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
-            integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
-            integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
-            populateInstallerExtras(integrityVerification);
-
-            // send to integrity component only.
-            integrityVerification.setPackage("android");
-
-            final BroadcastOptions options = BroadcastOptions.makeBasic();
-
-            mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
-                    /* receiverPermission= */ null,
-                    /* appOp= */ AppOpsManager.OP_NONE,
-                    /* options= */ options.toBundle(),
-                    new BroadcastReceiver() {
-                        @Override
-                        public void onReceive(Context context, Intent intent) {
-                            final Message msg =
-                                    mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
-                            msg.arg1 = verificationId;
-                            mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
-                        }
-                    }, /* scheduler= */ null,
-                    /* initialCode= */ 0,
-                    /* initialData= */ null,
-                    /* initialExtras= */ null);
-
-            Trace.asyncTraceBegin(
-                    TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
-
-            // stop the copy until verification succeeds.
-            mWaitForIntegrityVerificationToComplete = true;
-        }
-
-        /**
-         * Send a request to verifier(s) to verify the package if necessary.
-         */
-        void sendPackageVerificationRequest(
-                int verificationId,
-                PackageInfoLite pkgLite,
-                PackageVerificationState verificationState) {
-
-            // TODO: http://b/22976637
-            // Apps installed for "all" users use the device owner to verify the app
-            UserHandle verifierUser = getUser();
-            if (verifierUser == UserHandle.ALL) {
-                verifierUser = UserHandle.SYSTEM;
-            }
-
-            /*
-             * Determine if we have any installed package verifiers. If we
-             * do, then we'll defer to them to verify the packages.
-             */
-            final int requiredUid = mRequiredVerifierPackage == null ? -1
-                    : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
-                            verifierUser.getIdentifier());
-            verificationState.setRequiredVerifierUid(requiredUid);
-            final int installerUid =
-                    verificationInfo == null ? -1 : verificationInfo.installerUid;
-            final boolean isVerificationEnabled = isVerificationEnabled(
-                    pkgLite, verifierUser.getIdentifier(), installFlags, installerUid);
-            final boolean isV4Signed =
-                    (signingDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
-            final boolean isIncrementalInstall =
-                    (mDataLoaderType == DataLoaderType.INCREMENTAL);
-            // NOTE: We purposefully skip verification for only incremental installs when there's
-            // a v4 signature block. Otherwise, proceed with verification as usual.
-            if (!origin.existing
-                    && isVerificationEnabled
-                    && (!isIncrementalInstall || !isV4Signed)) {
-                final Intent verification = new Intent(
-                        Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
-                verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
-                        PACKAGE_MIME_TYPE);
-                verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-                // Query all live verifiers based on current user state
-                final List<ResolveInfo> receivers = queryIntentReceiversInternal(verification,
-                        PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(),
-                        false /*allowDynamicSplits*/);
-
-                if (DEBUG_VERIFY) {
-                    Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
-                            + verification.toString() + " with " + pkgLite.verifiers.length
-                            + " optional verifiers");
-                }
-
-                verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
-
-                verification.putExtra(
-                        PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, installFlags);
-
-                verification.putExtra(
-                        PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
-
-                verification.putExtra(
-                        PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
-
-                verification.putExtra(
-                        PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
-                        pkgLite.getLongVersionCode());
-
-                populateInstallerExtras(verification);
-
-                final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
-                        receivers, verificationState);
-
-                DeviceIdleInternal idleController =
-                        mInjector.getLocalService(DeviceIdleInternal.class);
-                final long idleDuration = getVerificationTimeout();
-                final BroadcastOptions options = BroadcastOptions.makeBasic();
-                options.setTemporaryAppAllowlist(idleDuration,
-                        TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
-                        REASON_PACKAGE_VERIFIER, "");
-
-                /*
-                 * If any sufficient verifiers were listed in the package
-                 * manifest, attempt to ask them.
-                 */
-                if (sufficientVerifiers != null) {
-                    final int n = sufficientVerifiers.size();
-                    if (n == 0) {
-                        String errorMsg = "Additional verifiers required, but none installed.";
-                        Slog.i(TAG, errorMsg);
-                        setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
-                    } else {
-                        for (int i = 0; i < n; i++) {
-                            final ComponentName verifierComponent = sufficientVerifiers.get(i);
-                            idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
-                                    verifierComponent.getPackageName(), idleDuration,
-                                    verifierUser.getIdentifier(), false,
-                                    REASON_PACKAGE_VERIFIER,"package verifier");
-
-                            final Intent sufficientIntent = new Intent(verification);
-                            sufficientIntent.setComponent(verifierComponent);
-                            mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
-                                    /* receiverPermission= */ null,
-                                    options.toBundle());
-                        }
-                    }
-                }
-
-                if (mRequiredVerifierPackage != null) {
-                    final ComponentName requiredVerifierComponent = matchComponentForVerifier(
-                            mRequiredVerifierPackage, receivers);
-                    /*
-                     * Send the intent to the required verification agent,
-                     * but only start the verification timeout after the
-                     * target BroadcastReceivers have run.
-                     */
-                    verification.setComponent(requiredVerifierComponent);
-                    idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
-                            mRequiredVerifierPackage, idleDuration,
-                            verifierUser.getIdentifier(), false,
-                            REASON_PACKAGE_VERIFIER, "package verifier");
-                    mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
-                            android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
-                            /* appOp= */ AppOpsManager.OP_NONE,
-                            /* options= */ options.toBundle(),
-                            new BroadcastReceiver() {
-                                @Override
-                                public void onReceive(Context context, Intent intent) {
-                                    final Message msg = mHandler
-                                            .obtainMessage(CHECK_PENDING_VERIFICATION);
-                                    msg.arg1 = verificationId;
-                                    mHandler.sendMessageDelayed(msg, getVerificationTimeout());
-                                }
-                            }, null, 0, null, null);
-
-                    Trace.asyncTraceBegin(
-                            TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
-                    /*
-                     * We don't want the copy to proceed until verification
-                     * succeeds.
-                     */
-                    mWaitForVerificationToComplete = true;
-                }
-            } else {
-                verificationState.setVerifierResponse(
-                        requiredUid, PackageManager.VERIFICATION_ALLOW);
-            }
-        }
-
-        void populateInstallerExtras(Intent intent) {
-            intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
-                    installSource.initiatingPackageName);
-
-            if (verificationInfo != null) {
-                if (verificationInfo.originatingUri != null) {
-                    intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
-                            verificationInfo.originatingUri);
-                }
-                if (verificationInfo.referrer != null) {
-                    intent.putExtra(Intent.EXTRA_REFERRER,
-                            verificationInfo.referrer);
-                }
-                if (verificationInfo.originatingUid >= 0) {
-                    intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
-                            verificationInfo.originatingUid);
-                }
-                if (verificationInfo.installerUid >= 0) {
-                    intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
-                            verificationInfo.installerUid);
-                }
-            }
-        }
-
-        void setReturnCode(int ret, String message) {
-            if (mRet == PackageManager.INSTALL_SUCCEEDED) {
-                // Only update mRet if it was previously INSTALL_SUCCEEDED to
-                // ensure we do not overwrite any previous failure results.
-                mRet = ret;
-                mErrorMessage = message;
-            }
-        }
-
-        void handleVerificationFinished() {
-            mWaitForVerificationToComplete = false;
-            handleReturnCode();
-        }
-
-        void handleIntegrityVerificationFinished() {
-            mWaitForIntegrityVerificationToComplete = false;
-            handleReturnCode();
-        }
-
-
-        void handleRollbackEnabled() {
-            // TODO(ruhler) b/112431924: Consider halting the install if we
-            // couldn't enable rollback.
-            mWaitForEnableRollbackToComplete = false;
-            handleReturnCode();
-        }
-
-        @Override
-        void handleReturnCode() {
-            if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
-                    || mWaitForEnableRollbackToComplete) {
-                return;
-            }
-            sendVerificationCompleteNotification();
-        }
-
-        private void sendVerificationCompleteNotification() {
-            if (mParentVerificationParams != null) {
-                mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
-            } else {
-                try {
-                    observer.onPackageInstalled(null, mRet, mErrorMessage,
-                            new Bundle());
-                } catch (RemoteException e) {
-                    Slog.i(TAG, "Observer no longer exists.");
-                }
-            }
-        }
-    }
-
-    private InstallArgs createInstallArgs(InstallParams params) {
-        if (params.move != null) {
-            return new MoveInstallArgs(params);
-        } else {
-            return new FileInstallArgs(params);
-        }
-    }
-
     /**
      * Create args that describe an existing installed package. Typically used
      * when cleaning up old installs, or used as a move source.
      */
-    private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
-        return new FileInstallArgs(codePath, instructionSets);
-    }
-
-    static abstract class InstallArgs {
-        /** @see InstallParams#origin */
-        final OriginInfo origin;
-        /** @see InstallParams#move */
-        final MoveInfo move;
-
-        final IPackageInstallObserver2 observer;
-        // Always refers to PackageManager flags only
-        final int installFlags;
-        @NonNull final InstallSource installSource;
-        final String volumeUuid;
-        final UserHandle user;
-        final String abiOverride;
-        final String[] installGrantPermissions;
-        final List<String> whitelistedRestrictedPermissions;
-        final int autoRevokePermissionsMode;
-        /** If non-null, drop an async trace when the install completes */
-        final String traceMethod;
-        final int traceCookie;
-        final SigningDetails signingDetails;
-        final int installReason;
-        final int mInstallScenario;
-        final boolean forceQueryableOverride;
-        final int mDataLoaderType;
-
-        // The list of instruction sets supported by this app. This is currently
-        // only used during the rmdex() phase to clean up resources. We can get rid of this
-        // if we move dex files under the common app path.
-        /* nullable */ String[] instructionSets;
-
-        InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
-                int installFlags, InstallSource installSource, String volumeUuid,
-                UserHandle user, String[] instructionSets,
-                String abiOverride, String[] installGrantPermissions,
-                List<String> whitelistedRestrictedPermissions,
-                int autoRevokePermissionsMode,
-                String traceMethod, int traceCookie, SigningDetails signingDetails,
-                int installReason, int installScenario, boolean forceQueryableOverride,
-                int dataLoaderType) {
-            this.origin = origin;
-            this.move = move;
-            this.installFlags = installFlags;
-            this.observer = observer;
-            this.installSource = Preconditions.checkNotNull(installSource);
-            this.volumeUuid = volumeUuid;
-            this.user = user;
-            this.instructionSets = instructionSets;
-            this.abiOverride = abiOverride;
-            this.installGrantPermissions = installGrantPermissions;
-            this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
-            this.autoRevokePermissionsMode = autoRevokePermissionsMode;
-            this.traceMethod = traceMethod;
-            this.traceCookie = traceCookie;
-            this.signingDetails = signingDetails;
-            this.installReason = installReason;
-            this.mInstallScenario = installScenario;
-            this.forceQueryableOverride = forceQueryableOverride;
-            this.mDataLoaderType = dataLoaderType;
-        }
-
-        /** New install */
-        InstallArgs(InstallParams params) {
-            this(params.origin, params.move, params.observer, params.installFlags,
-                    params.installSource, params.volumeUuid,
-                    params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
-                    params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
-                    params.autoRevokePermissionsMode,
-                    params.traceMethod, params.traceCookie, params.signingDetails,
-                    params.installReason, params.mInstallScenario, params.forceQueryableOverride,
-                    params.mDataLoaderType);
-        }
-
-        abstract int copyApk();
-        abstract int doPreInstall(int status);
-
-        /**
-         * Rename package into final resting place. All paths on the given
-         * scanned package should be updated to reflect the rename.
-         */
-        abstract boolean doRename(int status, ParsedPackage parsedPackage);
-        abstract int doPostInstall(int status, int uid);
-
-        /** @see PackageSettingBase#getPath() */
-        abstract String getCodePath();
-
-        // Need installer lock especially for dex file removal.
-        abstract void cleanUpResourcesLI();
-        abstract boolean doPostDeleteLI(boolean delete);
-
-        /**
-         * Called before the source arguments are copied. This is used mostly
-         * for MoveParams when it needs to read the source file to put it in the
-         * destination.
-         */
-        int doPreCopy() {
-            return PackageManager.INSTALL_SUCCEEDED;
-        }
-
-        /**
-         * Called after the source arguments are copied. This is used mostly for
-         * MoveParams when it needs to read the source file to put it in the
-         * destination.
-         */
-        int doPostCopy(int uid) {
-            return PackageManager.INSTALL_SUCCEEDED;
-        }
-
-        protected boolean isEphemeral() {
-            return (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-        }
-
-        UserHandle getUser() {
-            return user;
-        }
-    }
-
-    void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
-        if (!allCodePaths.isEmpty()) {
-            if (instructionSets == null) {
-                throw new IllegalStateException("instructionSet == null");
-            }
-            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-            for (String codePath : allCodePaths) {
-                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                    try {
-                        mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                    } catch (InstallerException ignored) {
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Logic to handle installation of new applications, including copying
-     * and renaming logic.
-     */
-    class FileInstallArgs extends InstallArgs {
-        private File codeFile;
-        private File resourceFile;
-
-        // Example topology:
-        // /data/app/com.example/base.apk
-        // /data/app/com.example/split_foo.apk
-        // /data/app/com.example/lib/arm/libfoo.so
-        // /data/app/com.example/lib/arm64/libfoo.so
-        // /data/app/com.example/dalvik/arm/base.apk@classes.dex
-
-        /** New install */
-        FileInstallArgs(InstallParams params) {
-            super(params);
-        }
-
-        /** Existing install */
-        FileInstallArgs(String codePath, String[] instructionSets) {
-            super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
-                    null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
-                    SigningDetails.UNKNOWN,
-                    PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
-                    false, DataLoaderType.NONE);
-            this.codeFile = (codePath != null) ? new File(codePath) : null;
-        }
-
-        int copyApk() {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
-            try {
-                return doCopyApk();
-            } finally {
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-        }
-
-        private int doCopyApk() {
-            if (origin.staged) {
-                if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
-                codeFile = origin.file;
-                return PackageManager.INSTALL_SUCCEEDED;
-            }
-
-            try {
-                final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-                final File tempDir =
-                        mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
-                codeFile = tempDir;
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to create copy file: " + e);
-                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
-
-            int ret = PackageManagerServiceUtils.copyPackage(
-                    origin.file.getAbsolutePath(), codeFile);
-            if (ret != PackageManager.INSTALL_SUCCEEDED) {
-                Slog.e(TAG, "Failed to copy package");
-                return ret;
-            }
-
-            final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
-            final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
-            NativeLibraryHelper.Handle handle = null;
-            try {
-                handle = NativeLibraryHelper.Handle.create(codeFile);
-                ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
-                        abiOverride, isIncremental);
-            } catch (IOException e) {
-                Slog.e(TAG, "Copying native libraries failed", e);
-                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-            } finally {
-                IoUtils.closeQuietly(handle);
-            }
-
-            return ret;
-        }
-
-        int doPreInstall(int status) {
-            if (status != PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp();
-            }
-            return status;
-        }
-
-        @Override
-        boolean doRename(int status, ParsedPackage parsedPackage) {
-            if (status != PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp();
-                return false;
-            }
-
-            final File targetDir = resolveTargetDir();
-            final File beforeCodeFile = codeFile;
-            final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
-
-            if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
-            final boolean onIncremental = mIncrementalManager != null
-                    && isIncrementalPath(beforeCodeFile.getAbsolutePath());
-            try {
-                makeDirRecursive(afterCodeFile.getParentFile(), 0775);
-                if (onIncremental) {
-                    // Just link files here. The stage dir will be removed when the installation
-                    // session is completed.
-                    mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
-                } else {
-                    Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
-                }
-            } catch (IOException | ErrnoException e) {
-                Slog.w(TAG, "Failed to rename", e);
-                return false;
-            }
-
-            if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
-                Slog.w(TAG, "Failed to restorecon");
-                return false;
-            }
-
-            // Reflect the rename internally
-            codeFile = afterCodeFile;
-
-            // Reflect the rename in scanned details
-            try {
-                parsedPackage.setPath(afterCodeFile.getCanonicalPath());
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
-                return false;
-            }
-            parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, parsedPackage.getBaseApkPath()));
-            parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, parsedPackage.getSplitCodePaths()));
-
-            return true;
-        }
-
-        // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
-        //  flow, we won't need this method anymore.
-        private File resolveTargetDir() {
-            boolean isStagedInstall = (installFlags & INSTALL_STAGED) != 0;
-            if (isStagedInstall) {
-                return Environment.getDataAppDirectory(null);
-            } else {
-                return codeFile.getParentFile();
-            }
-        }
-
-        int doPostInstall(int status, int uid) {
-            if (status != PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp();
-            }
-            return status;
-        }
-
-        @Override
-        String getCodePath() {
-            return (codeFile != null) ? codeFile.getAbsolutePath() : null;
-        }
-
-        private boolean cleanUp() {
-            if (codeFile == null || !codeFile.exists()) {
-                return false;
-            }
-            removeCodePathLI(codeFile);
-            return true;
-        }
-
-        void cleanUpResourcesLI() {
-            // Try enumerating all code paths before deleting
-            List<String> allCodePaths = Collections.EMPTY_LIST;
-            if (codeFile != null && codeFile.exists()) {
-                final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-                final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
-                        input.reset(), codeFile, /* flags */ 0);
-                if (result.isSuccess()) {
-                    // Ignore error; we tried our best
-                    allCodePaths = result.getResult().getAllApkPaths();
-                }
-            }
-
-            cleanUp();
-            removeDexFiles(allCodePaths, instructionSets);
-        }
-
-        boolean doPostDeleteLI(boolean delete) {
-            // XXX err, shouldn't we respect the delete flag?
-            cleanUpResourcesLI();
-            return true;
-        }
-    }
-
-    /**
-     * Logic to handle movement of existing installed applications.
-     */
-    class MoveInstallArgs extends InstallArgs {
-        private File codeFile;
-
-        /** New install */
-        MoveInstallArgs(InstallParams params) {
-            super(params);
-        }
-
-        int copyApk() {
-            if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
-                    + move.fromUuid + " to " + move.toUuid);
-            synchronized (mInstaller) {
-                try {
-                    mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
-                            move.appId, move.seinfo, move.targetSdkVersion,
-                            move.fromCodePath);
-                } catch (InstallerException e) {
-                    Slog.w(TAG, "Failed to move app", e);
-                    return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-                }
-            }
-
-            final String toPathName = new File(move.fromCodePath).getName();
-            codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
-            if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
-
-            return PackageManager.INSTALL_SUCCEEDED;
-        }
-
-        int doPreInstall(int status) {
-            if (status != PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp(move.toUuid);
-            }
-            return status;
-        }
-
-        @Override
-        boolean doRename(int status, ParsedPackage parsedPackage) {
-            if (status != PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp(move.toUuid);
-                return false;
-            }
-
-            return true;
-        }
-
-        int doPostInstall(int status, int uid) {
-            if (status == PackageManager.INSTALL_SUCCEEDED) {
-                cleanUp(move.fromUuid);
-            } else {
-                cleanUp(move.toUuid);
-            }
-            return status;
-        }
-
-        @Override
-        String getCodePath() {
-            return (codeFile != null) ? codeFile.getAbsolutePath() : null;
-        }
-
-        private boolean cleanUp(String volumeUuid) {
-            final String toPathName = new File(move.fromCodePath).getName();
-            final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
-                    toPathName);
-            Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
-            final int[] userIds = mUserManager.getUserIds();
-            synchronized (mInstallLock) {
-                // Clean up both app data and code
-                // All package moves are frozen until finished
-
-                // We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
-                // this task was only focused on moving data on internal storage.
-                // We don't want ART profiles cleared, because they don't move,
-                // so we would be deleting the only copy (b/149200535).
-                final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
-                        | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
-                for (int userId : userIds) {
-                    try {
-                        mInstaller.destroyAppData(volumeUuid, move.packageName, userId, flags, 0);
-                    } catch (InstallerException e) {
-                        Slog.w(TAG, String.valueOf(e));
-                    }
-                }
-                removeCodePathLI(codeFile);
-            }
-            return true;
-        }
-
-        void cleanUpResourcesLI() {
-            throw new UnsupportedOperationException();
-        }
-
-        boolean doPostDeleteLI(boolean delete) {
-            throw new UnsupportedOperationException();
-        }
+    InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
+        return new FileInstallArgs(codePath, instructionSets, this);
     }
 
     /**
@@ -19008,7 +17081,7 @@
      *                    directory.
      * @return File object for the directory that should hold the code files of {@code packageName}.
      */
-    private File getNextCodePath(File targetDir, String packageName) {
+    static File getNextCodePath(File targetDir, String packageName) {
         SecureRandom random = new SecureRandom();
         byte[] bytes = new byte[16];
         File firstLevelDir;
@@ -19023,54 +17096,6 @@
         return new File(firstLevelDir, packageName + "-" + suffix);
     }
 
-    static class PackageInstalledInfo {
-        String name;
-        int uid;
-        // The set of users that originally had this package installed.
-        int[] origUsers;
-        // The set of users that now have this package installed.
-        int[] newUsers;
-        AndroidPackage pkg;
-        int returnCode;
-        String returnMsg;
-        String installerPackageName;
-        PackageRemovedInfo removedInfo;
-        // The set of packages consuming this shared library or null if no consumers exist.
-        ArrayList<AndroidPackage> libraryConsumers;
-        PackageFreezer freezer;
-
-        public void setError(int code, String msg) {
-            setReturnCode(code);
-            setReturnMessage(msg);
-            Slog.w(TAG, msg);
-        }
-
-        public void setError(String msg, PackageManagerException e) {
-            returnCode = e.error;
-            setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
-            Slog.w(TAG, msg, e);
-        }
-
-        public void setReturnCode(int returnCode) {
-            this.returnCode = returnCode;
-        }
-
-        private void setReturnMessage(String returnMsg) {
-            this.returnMsg = returnMsg;
-        }
-
-        // In some error cases we want to convey more info back to the observer
-        String origPackage;
-        String origPermission;
-    }
-
-    private static void updateDigest(MessageDigest digest, File file) throws IOException {
-        try (DigestInputStream digestStream =
-                new DigestInputStream(new FileInputStream(file), digest)) {
-            while (digestStream.read() != -1) {} // nothing to do; just plow through the file
-        }
-    }
-
     private void removeNativeBinariesLI(PackageSetting ps) {
         if (ps != null) {
             NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
@@ -19083,361 +17108,18 @@
     }
 
     @GuardedBy("mLock")
-    private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
-        return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
-    }
-
-    private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
-            int[] allUsers, PackageInstalledInfo res) {
-        updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
-    }
-
-    private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
-            int[] allUsers, PackageInstalledInfo res) {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
-
-        final String pkgName = pkg.getPackageName();
-        final int[] installedForUsers = res.origUsers;
-        final int installReason = installArgs.installReason;
-        InstallSource installSource = installArgs.installSource;
-        final String installerPackageName = installSource.installerPackageName;
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
-        synchronized (mLock) {
-            // For system-bundled packages, we assume that installing an upgraded version
-            // of the package implies that the user actually wants to run that new code,
-            // so we enable the package.
-            final PackageSetting ps = mSettings.getPackageLPr(pkgName);
-            final int userId = installArgs.user.getIdentifier();
-            if (ps != null) {
-                if (pkg.isSystem()) {
-                    if (DEBUG_INSTALL) {
-                        Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
-                    }
-                    // Enable system package for requested users
-                    if (res.origUsers != null) {
-                        for (int origUserId : res.origUsers) {
-                            if (userId == UserHandle.USER_ALL || userId == origUserId) {
-                                ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
-                                        origUserId, installerPackageName);
-                            }
-                        }
-                    }
-                    // Also convey the prior install/uninstall state
-                    if (allUsers != null && installedForUsers != null) {
-                        for (int currentUserId : allUsers) {
-                            final boolean installed = ArrayUtils.contains(
-                                    installedForUsers, currentUserId);
-                            if (DEBUG_INSTALL) {
-                                Slog.d(TAG, "    user " + currentUserId + " => " + installed);
-                            }
-                            ps.setInstalled(installed, currentUserId);
-                        }
-                        // these install state changes will be persisted in the
-                        // upcoming call to mSettings.writeLPr().
-                    }
-
-                    if (allUsers != null) {
-                        for (int currentUserId : allUsers) {
-                            ps.resetOverrideComponentLabelIcon(currentUserId);
-                        }
-                    }
-                }
-
-                // Retrieve the overlays for shared libraries of the package.
-                if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) {
-                    for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) {
-                        for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
-                            if (!sharedLib.isDynamic()) {
-                                // TODO(146804378): Support overlaying static shared libraries
-                                continue;
-                            }
-                            final PackageSetting libPs = mSettings.getPackageLPr(
-                                    sharedLib.getPackageName());
-                            if (libPs == null) {
-                                continue;
-                            }
-                            ps.setOverlayPathsForLibrary(sharedLib.getName(),
-                                    libPs.getOverlayPaths(currentUserId), currentUserId);
-                        }
-                    }
-                }
-
-                // It's implied that when a user requests installation, they want the app to be
-                // installed and enabled. (This does not apply to USER_ALL, which here means only
-                // install on users for which the app is already installed).
-                if (userId != UserHandle.USER_ALL) {
-                    ps.setInstalled(true, userId);
-                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
-                }
-
-                mSettings.addInstallerPackageNames(ps.installSource);
-
-                // When replacing an existing package, preserve the original install reason for all
-                // users that had the package installed before. Similarly for uninstall reasons.
-                final Set<Integer> previousUserIds = new ArraySet<>();
-                if (res.removedInfo != null && res.removedInfo.installReasons != null) {
-                    final int installReasonCount = res.removedInfo.installReasons.size();
-                    for (int i = 0; i < installReasonCount; i++) {
-                        final int previousUserId = res.removedInfo.installReasons.keyAt(i);
-                        final int previousInstallReason = res.removedInfo.installReasons.valueAt(i);
-                        ps.setInstallReason(previousInstallReason, previousUserId);
-                        previousUserIds.add(previousUserId);
-                    }
-                }
-                if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) {
-                    for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) {
-                        final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i);
-                        final int previousReason = res.removedInfo.uninstallReasons.valueAt(i);
-                        ps.setUninstallReason(previousReason, previousUserId);
-                    }
-                }
-
-                // Set install reason for users that are having the package newly installed.
-                final int[] allUsersList = mUserManager.getUserIds();
-                if (userId == UserHandle.USER_ALL) {
-                    // TODO(b/152629990): It appears that the package doesn't actually get newly
-                    //  installed in this case, so the installReason shouldn't get modified?
-                    for (int currentUserId : allUsersList) {
-                        if (!previousUserIds.contains(currentUserId)) {
-                            ps.setInstallReason(installReason, currentUserId);
-                        }
-                    }
-                } else if (!previousUserIds.contains(userId)) {
-                    ps.setInstallReason(installReason, userId);
-                }
-
-                // TODO(b/169721400): generalize Incremental States and create a Callback object
-                // that can be used for all the packages.
-                final String codePath = ps.getPathString();
-                if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) {
-                    final IncrementalStatesCallback incrementalStatesCallback =
-                            new IncrementalStatesCallback(ps.name,
-                                    UserHandle.getUid(userId, ps.appId),
-                                    getInstalledUsers(ps, userId));
-                    ps.setIncrementalStatesCallback(incrementalStatesCallback);
-                    mIncrementalManager.registerLoadingProgressCallback(codePath,
-                            new IncrementalProgressListener(ps.name));
-                }
-
-                // Ensure that the uninstall reason is UNKNOWN for users with the package installed.
-                for (int currentUserId : allUsersList) {
-                    if (ps.getInstalled(currentUserId)) {
-                        ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId);
-                    }
-                }
-
-                mSettings.writeKernelMappingLPr(ps);
-
-                final PermissionManagerServiceInternal.PackageInstalledParams.Builder
-                        permissionParamsBuilder =
-                        new PermissionManagerServiceInternal.PackageInstalledParams.Builder();
-                final boolean grantPermissions = (installArgs.installFlags
-                        & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
-                if (grantPermissions) {
-                    final List<String> grantedPermissions =
-                            installArgs.installGrantPermissions != null
-                                    ? Arrays.asList(installArgs.installGrantPermissions)
-                                    : pkg.getRequestedPermissions();
-                    permissionParamsBuilder.setGrantedPermissions(grantedPermissions);
-                }
-                final boolean allowlistAllRestrictedPermissions =
-                        (installArgs.installFlags
-                                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0;
-                final List<String> allowlistedRestrictedPermissions =
-                        allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions()
-                        : installArgs.whitelistedRestrictedPermissions;
-                if (allowlistedRestrictedPermissions != null) {
-                    permissionParamsBuilder.setAllowlistedRestrictedPermissions(
-                            allowlistedRestrictedPermissions);
-                }
-                final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode;
-                permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
-                mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId);
-            }
-            res.name = pkgName;
-            res.uid = pkg.getUid();
-            res.pkg = pkg;
-            res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-            //to update install status
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
-            writeSettingsLPrTEMP();
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-
-        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-    }
-
-    private static class InstallRequest {
-        public final InstallArgs args;
-        public final PackageInstalledInfo installResult;
-
-        private InstallRequest(InstallArgs args, PackageInstalledInfo res) {
-            this.args = args;
-            this.installResult = res;
-        }
-    }
-
-    @GuardedBy("mInstallLock")
-    private void installPackagesTracedLI(List<InstallRequest> requests) {
-        try {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
-            installPackagesLI(requests);
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
-
-    /**
-     * Package state to commit to memory and disk after reconciliation has completed.
-     */
-    private static class CommitRequest {
-        final Map<String, ReconciledPackage> reconciledPackages;
-        @NonNull
-        final int[] mAllUsers;
-
-        private CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
-                @NonNull int[] allUsers) {
-            this.reconciledPackages = reconciledPackages;
-            this.mAllUsers = allUsers;
-        }
-    }
-
-    /**
-     * Package scan results and related request details used to reconcile the potential addition of
-     * one or more packages to the system.
-     *
-     * Reconcile will take a set of package details that need to be committed to the system and make
-     * sure that they are valid in the context of the system and the other installing apps. Any
-     * invalid state or app will result in a failed reconciliation and thus whatever operation (such
-     * as install) led to the request.
-     */
-    private static class ReconcileRequest {
-        public final Map<String, ScanResult> scannedPackages;
-
-        public final Map<String, AndroidPackage> allPackages;
-        public final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
-        public final Map<String, InstallArgs> installArgs;
-        public final Map<String, PackageInstalledInfo> installResults;
-        public final Map<String, PrepareResult> preparedPackages;
-        public final Map<String, VersionInfo> versionInfos;
-        public final Map<String, PackageSetting> lastStaticSharedLibSettings;
-
-        private ReconcileRequest(Map<String, ScanResult> scannedPackages,
-                Map<String, InstallArgs> installArgs,
-                Map<String, PackageInstalledInfo> installResults,
-                Map<String, PrepareResult> preparedPackages,
-                Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, AndroidPackage> allPackages,
-                Map<String, VersionInfo> versionInfos,
-                Map<String, PackageSetting> lastStaticSharedLibSettings) {
-            this.scannedPackages = scannedPackages;
-            this.installArgs = installArgs;
-            this.installResults = installResults;
-            this.preparedPackages = preparedPackages;
-            this.sharedLibrarySource = sharedLibrarySource;
-            this.allPackages = allPackages;
-            this.versionInfos = versionInfos;
-            this.lastStaticSharedLibSettings = lastStaticSharedLibSettings;
-        }
-
-        private ReconcileRequest(Map<String, ScanResult> scannedPackages,
-                Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, AndroidPackage> allPackages,
-                Map<String, VersionInfo> versionInfos,
-                Map<String, PackageSetting> lastStaticSharedLibSettings) {
-            this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
-                    Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
-                    lastStaticSharedLibSettings);
-        }
-    }
-    private static class ReconcileFailure extends PackageManagerException {
-        ReconcileFailure(String message) {
-            super("Reconcile failed: " + message);
-        }
-        ReconcileFailure(int reason, String message) {
-            super(reason, "Reconcile failed: " + message);
-        }
-        ReconcileFailure(PackageManagerException e) {
-            this(e.error, e.getMessage());
-        }
-    }
-
-    /**
-     * A container of all data needed to commit a package to in-memory data structures and to disk.
-     * TODO: move most of the data contained here into a PackageSetting for commit.
-     */
-    private static class ReconciledPackage {
-        public final ReconcileRequest request;
-        public final PackageSetting pkgSetting;
-        public final ScanResult scanResult;
-        // TODO: Remove install-specific details from the reconcile result
-        public final PackageInstalledInfo installResult;
-        @Nullable public final PrepareResult prepareResult;
-        @Nullable public final InstallArgs installArgs;
-        public final DeletePackageAction deletePackageAction;
-        public final List<SharedLibraryInfo> allowedSharedLibraryInfos;
-        public final SigningDetails signingDetails;
-        public final boolean sharedUserSignaturesChanged;
-        public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
-        public final boolean removeAppKeySetData;
-
-        private ReconciledPackage(ReconcileRequest request,
-                InstallArgs installArgs,
-                PackageSetting pkgSetting,
-                PackageInstalledInfo installResult,
-                PrepareResult prepareResult,
-                ScanResult scanResult,
-                DeletePackageAction deletePackageAction,
-                List<SharedLibraryInfo> allowedSharedLibraryInfos,
-                SigningDetails signingDetails,
-                boolean sharedUserSignaturesChanged,
-                boolean removeAppKeySetData) {
-            this.request = request;
-            this.installArgs = installArgs;
-            this.pkgSetting = pkgSetting;
-            this.installResult = installResult;
-            this.prepareResult = prepareResult;
-            this.scanResult = scanResult;
-            this.deletePackageAction = deletePackageAction;
-            this.allowedSharedLibraryInfos = allowedSharedLibraryInfos;
-            this.signingDetails = signingDetails;
-            this.sharedUserSignaturesChanged = sharedUserSignaturesChanged;
-            this.removeAppKeySetData = removeAppKeySetData;
-        }
-
-        /**
-         * Returns a combined set of packages containing the packages already installed combined
-         * with the package(s) currently being installed. The to-be installed packages take
-         * precedence and may shadow already installed packages.
-         */
-        private Map<String, AndroidPackage> getCombinedAvailablePackages() {
-            final ArrayMap<String, AndroidPackage> combined =
-                    new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
-
-            combined.putAll(request.allPackages);
-
-            for (ScanResult scanResult : request.scannedPackages.values()) {
-                combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
-            }
-
-            return combined;
-        }
-    }
-
-    @GuardedBy("mLock")
-    private static Map<String, ReconciledPackage> reconcilePackagesLocked(
+    static Map<String, ReconciledPackage> reconcilePackagesLocked(
             final ReconcileRequest request, KeySetManagerService ksms, Injector injector)
             throws ReconcileFailure {
-        final Map<String, ScanResult> scannedPackages = request.scannedPackages;
+        final Map<String, ScanResult> scannedPackages = request.mScannedPackages;
 
         final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
 
         // make a copy of the existing set of packages so we can combine them with incoming packages
         final ArrayMap<String, AndroidPackage> combinedPackages =
-                new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+                new ArrayMap<>(request.mAllPackages.size() + scannedPackages.size());
 
-        combinedPackages.putAll(request.allPackages);
+        combinedPackages.putAll(request.mAllPackages);
 
         final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
                 new ArrayMap<>();
@@ -19446,12 +17128,12 @@
             final ScanResult scanResult = scannedPackages.get(installPackageName);
 
             // add / replace existing with incoming packages
-            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
+            combinedPackages.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage);
 
             // in the first pass, we'll build up the set of incoming shared libraries
             final List<SharedLibraryInfo> allowedSharedLibInfos =
-                    getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource);
-            final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo;
+                    getAllowedSharedLibInfos(scanResult, request.mSharedLibrarySource);
+            final SharedLibraryInfo staticLib = scanResult.mStaticSharedLibraryInfo;
             if (allowedSharedLibInfos != null) {
                 for (SharedLibraryInfo info : allowedSharedLibInfos) {
                     if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) {
@@ -19462,9 +17144,9 @@
             }
 
             // the following may be null if we're just reconciling on boot (and not during install)
-            final InstallArgs installArgs = request.installArgs.get(installPackageName);
-            final PackageInstalledInfo res = request.installResults.get(installPackageName);
-            final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
+            final InstallArgs installArgs = request.mInstallArgs.get(installPackageName);
+            final PackageInstalledInfo res = request.mInstallResults.get(installPackageName);
+            final PrepareResult prepareResult = request.mPreparedPackages.get(installPackageName);
             final boolean isInstall = installArgs != null;
             if (isInstall && (res == null || prepareResult == null)) {
                 throw new ReconcileFailure("Reconcile arguments are not balanced for "
@@ -19473,12 +17155,12 @@
 
             final DeletePackageAction deletePackageAction;
             // we only want to try to delete for non system apps
-            if (isInstall && prepareResult.replace && !prepareResult.system) {
-                final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0;
+            if (isInstall && prepareResult.mReplace && !prepareResult.mSystem) {
+                final boolean killApp = (scanResult.mRequest.mScanFlags & SCAN_DONT_KILL_APP) == 0;
                 final int deleteFlags = PackageManager.DELETE_KEEP_DATA
                         | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
-                deletePackageAction = mayDeletePackageLocked(res.removedInfo,
-                        prepareResult.originalPs, prepareResult.disabledPs,
+                deletePackageAction = mayDeletePackageLocked(res.mRemovedInfo,
+                        prepareResult.mOriginalPs, prepareResult.mDisabledPs,
                         deleteFlags, null /* all users */);
                 if (deletePackageAction == null) {
                     throw new ReconcileFailure(
@@ -19489,17 +17171,17 @@
                 deletePackageAction = null;
             }
 
-            final int scanFlags = scanResult.request.scanFlags;
-            final int parseFlags = scanResult.request.parseFlags;
-            final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
+            final int scanFlags = scanResult.mRequest.mScanFlags;
+            final int parseFlags = scanResult.mRequest.mParseFlags;
+            final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
 
-            final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
+            final PackageSetting disabledPkgSetting = scanResult.mRequest.mDisabledPkgSetting;
             final PackageSetting lastStaticSharedLibSetting =
-                    request.lastStaticSharedLibSettings.get(installPackageName);
+                    request.mLastStaticSharedLibSettings.get(installPackageName);
             final PackageSetting signatureCheckPs =
                     (prepareResult != null && lastStaticSharedLibSetting != null)
                             ? lastStaticSharedLibSetting
-                            : scanResult.pkgSetting;
+                            : scanResult.mPkgSetting;
             boolean removeAppKeySetData = false;
             boolean sharedUserSignaturesChanged = false;
             SigningDetails signingDetails = null;
@@ -19522,11 +17204,11 @@
                 signingDetails = parsedPackage.getSigningDetails();
             } else {
                 try {
-                    final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
+                    final VersionInfo versionInfo = request.mVersionInfos.get(installPackageName);
                     final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
                     final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
                     final boolean isRollback = installArgs != null
-                            && installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+                            && installArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
                     final boolean compatMatch = verifySignatures(signatureCheckPs,
                             disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
                             compareRecover, isRollback);
@@ -19590,7 +17272,7 @@
                                 throw new ReconcileFailure(
                                         INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                                         "Signature mismatch for shared user: "
-                                                + scanResult.pkgSetting.sharedUser);
+                                                + scanResult.mPkgSetting.sharedUser);
                             } else {
                                 // Treat mismatched signatures on system packages using a shared
                                 // UID as
@@ -19600,7 +17282,7 @@
                                         "Signature mismatch on system package "
                                                 + parsedPackage.getPackageName()
                                                 + " for shared user "
-                                                + scanResult.pkgSetting.sharedUser);
+                                                + scanResult.mPkgSetting.sharedUser);
                             }
                         }
 
@@ -19623,8 +17305,8 @@
             }
 
             result.put(installPackageName,
-                    new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
-                            res, request.preparedPackages.get(installPackageName), scanResult,
+                    new ReconciledPackage(request, installArgs, scanResult.mPkgSetting,
+                            res, request.mPreparedPackages.get(installPackageName), scanResult,
                             deletePackageAction, allowedSharedLibInfos, signingDetails,
                             sharedUserSignaturesChanged, removeAppKeySetData));
         }
@@ -19638,15 +17320,15 @@
             // scan don't update any libs as we do this wholesale after all
             // apps are scanned to avoid dependency based scanning.
             final ScanResult scanResult = scannedPackages.get(installPackageName);
-            if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0
-                    || (scanResult.request.parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
+            if ((scanResult.mRequest.mScanFlags & SCAN_BOOTING) != 0
+                    || (scanResult.mRequest.mParseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
                     != 0) {
                 continue;
             }
             try {
-                result.get(installPackageName).collectedSharedLibraryInfos =
-                        collectSharedLibraryInfos(scanResult.request.parsedPackage,
-                                combinedPackages, request.sharedLibrarySource,
+                result.get(installPackageName).mCollectedSharedLibraryInfos =
+                        collectSharedLibraryInfos(scanResult.mRequest.mParsedPackage,
+                                combinedPackages, request.mSharedLibrarySource,
                                 incomingSharedLibraries, injector.getCompatibility());
 
             } catch (PackageManagerException e) {
@@ -19665,29 +17347,29 @@
             ScanResult scanResult,
             Map<String, WatchedLongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
         // Let's used the parsed package as scanResult.pkgSetting may be null
-        final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
-        if (scanResult.staticSharedLibraryInfo == null
-                && scanResult.dynamicSharedLibraryInfos == null) {
+        final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage;
+        if (scanResult.mStaticSharedLibraryInfo == null
+                && scanResult.mDynamicSharedLibraryInfos == null) {
             return null;
         }
 
         // Any app can add new static shared libraries
-        if (scanResult.staticSharedLibraryInfo != null) {
-            return Collections.singletonList(scanResult.staticSharedLibraryInfo);
+        if (scanResult.mStaticSharedLibraryInfo != null) {
+            return Collections.singletonList(scanResult.mStaticSharedLibraryInfo);
         }
         final boolean hasDynamicLibraries = parsedPackage.isSystem()
-                        && scanResult.dynamicSharedLibraryInfos != null;
+                        && scanResult.mDynamicSharedLibraryInfos != null;
         if (!hasDynamicLibraries) {
             return null;
         }
-        final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState()
+        final boolean isUpdatedSystemApp = scanResult.mPkgSetting.getPkgState()
                 .isUpdatedSystemApp();
         // We may not yet have disabled the updated package yet, so be sure to grab the
         // current setting if that's the case.
         final PackageSetting updatedSystemPs = isUpdatedSystemApp
-                ? scanResult.request.disabledPkgSetting == null
-                        ? scanResult.request.oldPkgSetting
-                        : scanResult.request.disabledPkgSetting
+                ? scanResult.mRequest.mDisabledPkgSetting == null
+                        ? scanResult.mRequest.mOldPkgSetting
+                        : scanResult.mRequest.mDisabledPkgSetting
                 : null;
         if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
                 || updatedSystemPs.pkg.getLibraryNames() == null)) {
@@ -19696,8 +17378,8 @@
             return null;
         }
         final ArrayList<SharedLibraryInfo> infos =
-                new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size());
-        for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) {
+                new ArrayList<>(scanResult.mDynamicSharedLibraryInfos.size());
+        for (SharedLibraryInfo info : scanResult.mDynamicSharedLibraryInfos) {
             final String name = info.getName();
             if (isUpdatedSystemApp) {
                 // New library entries can only be added through the
@@ -19751,509 +17433,6 @@
         return true;
     }
 
-    @GuardedBy("mLock")
-    private void commitPackagesLocked(final CommitRequest request) {
-        // TODO: remove any expected failures from this method; this should only be able to fail due
-        //       to unavoidable errors (I/O, etc.)
-        for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
-            final ScanResult scanResult = reconciledPkg.scanResult;
-            final ScanRequest scanRequest = scanResult.request;
-            final ParsedPackage parsedPackage = scanRequest.parsedPackage;
-            final String packageName = parsedPackage.getPackageName();
-            final PackageInstalledInfo res = reconciledPkg.installResult;
-
-            if (reconciledPkg.prepareResult.replace) {
-                AndroidPackage oldPackage = mPackages.get(packageName);
-
-                // Set the update and install times
-                PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());
-                reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
-                reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
-
-                res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                        reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked());
-                if (reconciledPkg.prepareResult.system) {
-                    // Remove existing system package
-                    removePackageLI(oldPackage, true);
-                    if (!disableSystemPackageLPw(oldPackage)) {
-                        // We didn't need to disable the .apk as a current system package,
-                        // which means we are replacing another update that is already
-                        // installed.  We need to make sure to delete the older one's .apk.
-                        res.removedInfo.args = createInstallArgsForExisting(
-                                oldPackage.getPath(),
-                                getAppDexInstructionSets(
-                                        AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
-                                                deletedPkgSetting),
-                                        AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
-                                                deletedPkgSetting)));
-                    } else {
-                        res.removedInfo.args = null;
-                    }
-                } else {
-                    try {
-                        // Settings will be written during the call to updateSettingsLI().
-                        executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
-                                true, request.mAllUsers, false, parsedPackage);
-                    } catch (SystemDeleteException e) {
-                        if (mIsEngBuild) {
-                            throw new RuntimeException("Unexpected failure", e);
-                            // ignore; not possible for non-system app
-                        }
-                    }
-                    // Successfully deleted the old package; proceed with replace.
-
-                    // If deleted package lived in a container, give users a chance to
-                    // relinquish resources before killing.
-                    if (oldPackage.isExternalStorage()) {
-                        if (DEBUG_INSTALL) {
-                            Slog.i(TAG, "upgrading pkg " + oldPackage
-                                    + " is ASEC-hosted -> UNAVAILABLE");
-                        }
-                        final int[] uidArray = new int[]{oldPackage.getUid()};
-                        final ArrayList<String> pkgList = new ArrayList<>(1);
-                        pkgList.add(oldPackage.getPackageName());
-                        sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
-                    }
-
-                    // Update the in-memory copy of the previous code paths.
-                    PackageSetting ps1 = mSettings.getPackageLPr(
-                            reconciledPkg.prepareResult.existingPackage.getPackageName());
-                    if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
-                            == 0) {
-                        if (ps1.mOldCodePaths == null) {
-                            ps1.mOldCodePaths = new ArraySet<>();
-                        }
-                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());
-                        if (oldPackage.getSplitCodePaths() != null) {
-                            Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
-                        }
-                    } else {
-                        ps1.mOldCodePaths = null;
-                    }
-
-                    if (reconciledPkg.installResult.returnCode
-                            == PackageManager.INSTALL_SUCCEEDED) {
-                        PackageSetting ps2 = mSettings.getPackageLPr(
-                                parsedPackage.getPackageName());
-                        if (ps2 != null) {
-                            res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
-                        }
-                    }
-                }
-            }
-
-            AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
-            updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
-
-            final PackageSetting ps = mSettings.getPackageLPr(packageName);
-            if (ps != null) {
-                res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
-                ps.setUpdateAvailable(false /*updateAvailable*/);
-            }
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSequenceNumberLP(ps, res.newUsers);
-                updateInstantAppInstallerLocked(packageName);
-            }
-        }
-        ApplicationPackageManager.invalidateGetPackagesForUidCache();
-    }
-
-    /**
-     * Installs one or more packages atomically. This operation is broken up into four phases:
-     * <ul>
-     *     <li><b>Prepare</b>
-     *         <br/>Analyzes any current install state, parses the package and does initial
-     *         validation on it.</li>
-     *     <li><b>Scan</b>
-     *         <br/>Interrogates the parsed packages given the context collected in prepare.</li>
-     *     <li><b>Reconcile</b>
-     *         <br/>Validates scanned packages in the context of each other and the current system
-     *         state to ensure that the install will be successful.
-     *     <li><b>Commit</b>
-     *         <br/>Commits all scanned packages and updates system state. This is the only place
-     *         that system state may be modified in the install flow and all predictable errors
-     *         must be determined before this phase.</li>
-     * </ul>
-     *
-     * Failure at any phase will result in a full failure to install all packages.
-     */
-    @GuardedBy("mInstallLock")
-    private void installPackagesLI(List<InstallRequest> requests) {
-        final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
-        final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
-        final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
-        final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
-        final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
-        final Map<String, PackageSetting> lastStaticSharedLibSettings =
-                new ArrayMap<>(requests.size());
-        final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
-        boolean success = false;
-        try {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
-            for (InstallRequest request : requests) {
-                // TODO(b/109941548): remove this once we've pulled everything from it and into
-                //                    scan, reconcile or commit.
-                final PrepareResult prepareResult;
-                try {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
-                    prepareResult =
-                            preparePackageLI(request.args, request.installResult);
-                } catch (PrepareFailure prepareFailure) {
-                    request.installResult.setError(prepareFailure.error,
-                            prepareFailure.getMessage());
-                    request.installResult.origPackage = prepareFailure.conflictingPackage;
-                    request.installResult.origPermission = prepareFailure.conflictingPermission;
-                    return;
-                } finally {
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-                request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                request.installResult.installerPackageName =
-                        request.args.installSource.installerPackageName;
-
-                final String packageName = prepareResult.packageToScan.getPackageName();
-                prepareResults.put(packageName, prepareResult);
-                installResults.put(packageName, request.installResult);
-                installArgs.put(packageName, request.args);
-                try {
-                    final ScanResult result = scanPackageTracedLI(
-                            prepareResult.packageToScan, prepareResult.parseFlags,
-                            prepareResult.scanFlags, System.currentTimeMillis(),
-                            request.args.user, request.args.abiOverride);
-                    if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
-                        request.installResult.setError(
-                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
-                                "Duplicate package " + result.pkgSetting.pkg.getPackageName()
-                                        + " in multi-package install request.");
-                        return;
-                    }
-                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
-                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
-                            getSettingsVersionForPackage(result.pkgSetting.pkg));
-                    if (result.staticSharedLibraryInfo != null) {
-                        final PackageSetting sharedLibLatestVersionSetting =
-                                getSharedLibLatestVersionSetting(result);
-                        if (sharedLibLatestVersionSetting != null) {
-                            lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
-                                    sharedLibLatestVersionSetting);
-                        }
-                    }
-                } catch (PackageManagerException e) {
-                    request.installResult.setError("Scanning Failed.", e);
-                    return;
-                }
-            }
-            ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
-                    installResults,
-                    prepareResults,
-                    mSharedLibraries,
-                    Collections.unmodifiableMap(mPackages), versionInfos,
-                    lastStaticSharedLibSettings);
-            CommitRequest commitRequest = null;
-            synchronized (mLock) {
-                Map<String, ReconciledPackage> reconciledPackages;
-                try {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
-                    reconciledPackages = reconcilePackagesLocked(
-                            reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
-                } catch (ReconcileFailure e) {
-                    for (InstallRequest request : requests) {
-                        request.installResult.setError("Reconciliation failed...", e);
-                    }
-                    return;
-                } finally {
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-                try {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
-                    commitRequest = new CommitRequest(reconciledPackages,
-                            mUserManager.getUserIds());
-                    commitPackagesLocked(commitRequest);
-                    success = true;
-                } finally {
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-            }
-            executePostCommitSteps(commitRequest);
-        } finally {
-            if (success) {
-                for (InstallRequest request : requests) {
-                    final InstallArgs args = request.args;
-                    if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
-                        continue;
-                    }
-                    if (args.signingDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) {
-                        continue;
-                    }
-                    // For incremental installs, we bypass the verifier prior to install. Now
-                    // that we know the package is valid, send a notice to the verifier with
-                    // the root hash of the base.apk.
-                    final String baseCodePath = request.installResult.pkg.getBaseApkPath();
-                    final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
-                    final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
-                    final int verificationId = mPendingVerificationToken++;
-                    final String rootHashString = PackageManagerServiceUtils
-                            .buildVerificationRootHashString(baseCodePath, splitCodePaths);
-                    broadcastPackageVerified(verificationId, originUri,
-                            PackageManager.VERIFICATION_ALLOW, rootHashString,
-                            args.mDataLoaderType, args.getUser());
-                }
-            } else {
-                for (ScanResult result : preparedScans.values()) {
-                    if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
-                            false)) {
-                        cleanUpAppIdCreation(result);
-                    }
-                }
-                // TODO(patb): create a more descriptive reason than unknown in future release
-                // mark all non-failure installs as UNKNOWN so we do not treat them as success
-                for (InstallRequest request : requests) {
-                    if (request.installResult.freezer != null) {
-                        request.installResult.freezer.close();
-                    }
-                    if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                        request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
-                    }
-                }
-            }
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        }
-    }
-
-    /**
-     * On successful install, executes remaining steps after commit completes and the package lock
-     * is released. These are typically more expensive or require calls to installd, which often
-     * locks on {@link #mLock}.
-     */
-    private void executePostCommitSteps(CommitRequest commitRequest) {
-        final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
-        for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
-            final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
-                            & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
-            final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
-            final String packageName = pkg.getPackageName();
-            final String codePath = pkg.getPath();
-            final boolean onIncremental = mIncrementalManager != null
-                    && isIncrementalPath(codePath);
-            if (onIncremental) {
-                IncrementalStorage storage = mIncrementalManager.openStorage(codePath);
-                if (storage == null) {
-                    throw new IllegalArgumentException(
-                            "Install: null storage for incremental package " + packageName);
-                }
-                incrementalStorages.add(storage);
-            }
-            prepareAppDataAfterInstallLIF(pkg);
-            if (reconciledPkg.prepareResult.clearCodeCache) {
-                clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
-                        | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-            }
-            if (reconciledPkg.prepareResult.replace) {
-                mDexManager.notifyPackageUpdated(pkg.getPackageName(),
-                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
-            }
-
-            // Prepare the application profiles for the new code paths.
-            // This needs to be done before invoking dexopt so that any install-time profile
-            // can be used for optimizations.
-            mArtManagerService.prepareAppProfiles(
-                    pkg,
-                    resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
-                    /* updateReferenceProfileContent= */ true);
-
-            // Compute the compilation reason from the installation scenario.
-            final int compilationReason = mDexManager.getCompilationReasonForInstallScenario(
-                    reconciledPkg.installArgs.mInstallScenario);
-
-            // Construct the DexoptOptions early to see if we should skip running dexopt.
-            //
-            // Do not run PackageDexOptimizer through the local performDexOpt
-            // method because `pkg` may not be in `mPackages` yet.
-            //
-            // Also, don't fail application installs if the dexopt step fails.
-            final boolean isBackupOrRestore =
-                    reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE
-                    || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP;
-
-            final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
-                    | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
-                    | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);
-            DexoptOptions dexoptOptions =
-                    new DexoptOptions(packageName, compilationReason, dexoptFlags);
-
-            // Check whether we need to dexopt the app.
-            //
-            // NOTE: it is IMPORTANT to call dexopt:
-            //   - after doRename which will sync the package data from AndroidPackage and
-            //     its corresponding ApplicationInfo.
-            //   - after installNewPackageLIF or replacePackageLIF which will update result with the
-            //     uid of the application (pkg.applicationInfo.uid).
-            //     This update happens in place!
-            //
-            // We only need to dexopt if the package meets ALL of the following conditions:
-            //   1) it is not an instant app or if it is then dexopt is enabled via gservices.
-            //   2) it is not debuggable.
-            //   3) it is not on Incremental File System.
-            //
-            // Note that we do not dexopt instant apps by default. dexopt can take some time to
-            // complete, so we skip this step during installation. Instead, we'll take extra time
-            // the first time the instant app starts. It's preferred to do it this way to provide
-            // continuous progress to the useur instead of mysteriously blocking somewhere in the
-            // middle of running an instant app. The default behaviour can be overridden
-            // via gservices.
-            //
-            // Furthermore, dexopt may be skipped, depending on the install scenario and current
-            // state of the device.
-            //
-            // TODO(b/174695087): instantApp and onIncremental should be removed and their install
-            //       path moved to SCENARIO_FAST.
-            final boolean performDexopt =
-                    (!instantApp || Global.getInt(mContext.getContentResolver(),
-                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                    && !pkg.isDebuggable()
-                    && (!onIncremental)
-                    && dexoptOptions.isCompilationEnabled();
-
-            if (performDexopt) {
-                // Compile the layout resources.
-                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
-                    mViewCompiler.compileLayouts(pkg);
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-                ScanResult result = reconciledPkg.scanResult;
-
-                // This mirrors logic from commitReconciledScanResultLocked, where the library files
-                // needed for dexopt are assigned.
-                // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous
-                //  setting needs to be passed to have a comparison, hide it behind an immutable
-                //  interface. There's no good reason to have 3 different ways to access the real
-                //  PackageSetting object, only one of which is actually correct.
-                PackageSetting realPkgSetting = result.existingSettingCopied
-                        ? result.request.pkgSetting : result.pkgSetting;
-                if (realPkgSetting == null) {
-                    realPkgSetting = reconciledPkg.pkgSetting;
-                }
-
-                // Unfortunately, the updated system app flag is only tracked on this PackageSetting
-                boolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState()
-                        .isUpdatedSystemApp();
-
-                realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
-
-                mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
-                        null /* instructionSets */,
-                        getOrCreateCompilerPackageStats(pkg),
-                        mDexManager.getPackageUseInfoOrDefault(packageName),
-                        dexoptOptions);
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-
-            // Notify BackgroundDexOptService that the package has been changed.
-            // If this is an update of a package which used to fail to compile,
-            // BackgroundDexOptService will remove it from its denylist.
-            // TODO: Layering violation
-            BackgroundDexOptService.notifyPackageChanged(packageName);
-
-            notifyPackageChangeObserversOnUpdate(reconciledPkg);
-        }
-        waitForNativeBinariesExtraction(incrementalStorages);
-    }
-
-    static void waitForNativeBinariesExtraction(
-            ArraySet<IncrementalStorage> incrementalStorages) {
-        if (incrementalStorages.isEmpty()) {
-            return;
-        }
-        try {
-            // Native library extraction may take very long time: each page could potentially
-            // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds
-            // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't
-            // make much sense as blocking here doesn't lock up the framework, but only blocks
-            // the installation session and the following ones.
-            Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract");
-            for (int i = 0; i < incrementalStorages.size(); ++i) {
-                IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i);
-                storage.waitForNativeBinariesExtraction();
-            }
-        } finally {
-            Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract");
-        }
-    }
-
-    private int[] getInstalledUsers(PackageSetting ps, int userId) {
-        final int[] allUserIds = resolveUserIds(userId);
-        final ArrayList<Integer> installedUserIdsList = new ArrayList<>();
-        for (int i = 0; i < allUserIds.length; i++) {
-            if (ps.getInstalled(allUserIds[i])) {
-                installedUserIdsList.add(allUserIds[i]);
-            }
-        }
-        final int numInstalledUserId = installedUserIdsList.size();
-        final int[] installedUserIds = new int[numInstalledUserId];
-        for (int i = 0; i < numInstalledUserId; i++) {
-            installedUserIds[i] = installedUserIdsList.get(i);
-        }
-        return installedUserIds;
-    }
-
-    /**
-     * Package states callback, used to listen for package state changes and send broadcasts
-     */
-    private final class IncrementalStatesCallback implements IncrementalStates.Callback {
-        private final String mPackageName;
-        private final int mUid;
-        private final int[] mInstalledUserIds;
-        IncrementalStatesCallback(String packageName, int uid, int[] installedUserIds) {
-            mPackageName = packageName;
-            mUid = uid;
-            mInstalledUserIds = installedUserIds;
-        }
-
-        @Override
-        public void onPackageFullyLoaded() {
-            final SparseArray<int[]> newBroadcastAllowList;
-            final String codePath;
-            synchronized (mLock) {
-                final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
-                if (ps == null) {
-                    return;
-                }
-                newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                        ps, mInstalledUserIds, mSettings.getPackagesLocked());
-                codePath = ps.getPathString();
-            }
-            // Unregister progress listener
-            mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
-            // Make sure the information is preserved
-            scheduleWriteSettingsLocked();
-        }
-    }
-
-    /**
-     * Loading progress callback, used to listen for progress changes and update package setting
-     */
-    private class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
-        private final String mPackageName;
-        IncrementalProgressListener(String packageName) {
-            mPackageName = packageName;
-        }
-
-        @Override
-        public void onPackageLoadingProgressChanged(float progress) {
-            final PackageSetting ps;
-            synchronized (mLock) {
-                ps = mSettings.getPackageLPr(mPackageName);
-                if (ps == null) {
-                    return;
-                }
-                ps.setLoadingProgress(progress);
-            }
-        }
-    }
-
     @Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid,
             int userId) {
         final PackageSetting ps;
@@ -20278,914 +17457,33 @@
         return ps;
     }
 
-    private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
-      final PackageSetting pkgSetting = reconciledPkg.pkgSetting;
-      final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult;
-      final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.removedInfo;
-
-      PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
-      pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName();
-      pkgChangeEvent.version = pkgSetting.versionCode;
-      pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime;
-      pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.isUpdate);
-      pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.dataRemoved);
-      pkgChangeEvent.isDeleted = false;
-
-      notifyPackageChangeObservers(pkgChangeEvent);
-    }
-
     private void notifyPackageChangeObserversOnDelete(String packageName, long version) {
-      PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
-      pkgChangeEvent.packageName = packageName;
-      pkgChangeEvent.version = version;
-      pkgChangeEvent.lastUpdateTimeMillis = 0L;
-      pkgChangeEvent.newInstalled = false;
-      pkgChangeEvent.dataRemoved = false;
-      pkgChangeEvent.isDeleted = true;
+        PackageChangeEvent pkgChangeEvent = new PackageChangeEvent();
+        pkgChangeEvent.packageName = packageName;
+        pkgChangeEvent.version = version;
+        pkgChangeEvent.lastUpdateTimeMillis = 0L;
+        pkgChangeEvent.newInstalled = false;
+        pkgChangeEvent.dataRemoved = false;
+        pkgChangeEvent.isDeleted = true;
 
-      notifyPackageChangeObservers(pkgChangeEvent);
+        notifyPackageChangeObservers(pkgChangeEvent);
     }
 
-    private void notifyPackageChangeObservers(PackageChangeEvent event) {
-      try {
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
-        synchronized (mPackageChangeObservers) {
-          for(IPackageChangeObserver observer : mPackageChangeObservers) {
-            try {
-              observer.onPackageChanged(event);
-            } catch(RemoteException e) {
-              Log.wtf(TAG, e);
-            }
-          }
-        }
-      } finally {
-        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-      }
-    }
-
-    /**
-     * The set of data needed to successfully install the prepared package. This includes data that
-     * will be used to scan and reconcile the package.
-     */
-    private static class PrepareResult {
-        public final boolean replace;
-        public final int scanFlags;
-        public final int parseFlags;
-        @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
-        public final AndroidPackage existingPackage;
-        public final ParsedPackage packageToScan;
-        public final boolean clearCodeCache;
-        public final boolean system;
-        public final PackageSetting originalPs;
-        public final PackageSetting disabledPs;
-
-        private PrepareResult(boolean replace, int scanFlags,
-                int parseFlags, AndroidPackage existingPackage,
-                ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
-                PackageSetting originalPs, PackageSetting disabledPs) {
-            this.replace = replace;
-            this.scanFlags = scanFlags;
-            this.parseFlags = parseFlags;
-            this.existingPackage = existingPackage;
-            this.packageToScan = packageToScan;
-            this.clearCodeCache = clearCodeCache;
-            this.system = system;
-            this.originalPs = originalPs;
-            this.disabledPs = disabledPs;
-        }
-    }
-
-    private static class PrepareFailure extends PackageManagerException {
-
-        public String conflictingPackage;
-        public String conflictingPermission;
-
-        PrepareFailure(int error) {
-            super(error, "Failed to prepare for install.");
-        }
-
-        PrepareFailure(int error, String detailMessage) {
-            super(error, detailMessage);
-        }
-
-        PrepareFailure(String message, Exception e) {
-            super(((PackageManagerException) e).error,
-                    ExceptionUtils.getCompleteMessage(message, e));
-        }
-
-        PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
-                String conflictingPackage) {
-            this.conflictingPermission = conflictingPermission;
-            this.conflictingPackage = conflictingPackage;
-            return this;
-        }
-    }
-
-    private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
-            @NonNull ParsedPackage parsedPackage, int scanFlags) {
-        // If the defining package is signed with our cert, it's okay.  This
-        // also includes the "updating the same package" case, of course.
-        // "updating same package" could also involve key-rotation.
-
-        final PackageSetting sourcePackageSetting;
-        synchronized (mLock) {
-            sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName);
-        }
-
-        final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
-                ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
-        final KeySetManagerService ksms = mSettings.getKeySetManagerService();
-        if (sourcePackageName.equals(parsedPackage.getPackageName())
-                && (ksms.shouldCheckUpgradeKeySetLocked(
-                sourcePackageSetting, scanFlags))) {
-            return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
-        } else {
-
-            // in the event of signing certificate rotation, we need to see if the
-            // package's certificate has rotated from the current one, or if it is an
-            // older certificate with which the current is ok with sharing permissions
-            if (sourceSigningDetails.checkCapability(
-                    parsedPackage.getSigningDetails(),
-                    SigningDetails.CertCapabilities.PERMISSION)) {
-                return true;
-            } else if (parsedPackage.getSigningDetails().checkCapability(
-                    sourceSigningDetails,
-                    SigningDetails.CertCapabilities.PERMISSION)) {
-                // the scanned package checks out, has signing certificate rotation
-                // history, and is newer; bring it over
-                synchronized (mLock) {
-                    sourcePackageSetting.signatures.mSigningDetails =
-                            parsedPackage.getSigningDetails();
+    void notifyPackageChangeObservers(PackageChangeEvent event) {
+        try {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers");
+            synchronized (mPackageChangeObservers) {
+                for (IPackageChangeObserver observer : mPackageChangeObservers) {
+                    try {
+                        observer.onPackageChanged(event);
+                    } catch (RemoteException e) {
+                        Log.wtf(TAG, e);
+                    }
                 }
-                return true;
-            } else {
-                return false;
             }
-        }
-    }
-
-    /*
-     * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges
-     * as this only works for packages that are installed
-     *
-     * TODO: Move logic for permission group compatibility into PermissionManagerService
-     */
-    @SuppressWarnings("AndroidFrameworkCompatChange")
-    private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) {
-        return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S;
-    }
-
-    @GuardedBy("mInstallLock")
-    private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
-            throws PrepareFailure {
-        final int installFlags = args.installFlags;
-        final File tmpPackageFile = new File(args.getCodePath());
-        final boolean onExternal = args.volumeUuid != null;
-        final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
-        final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
-        final boolean virtualPreload =
-                ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
-        final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
-        @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
-        if (args.move != null) {
-            // moving a complete application; perform an initial scan on the new install location
-            scanFlags |= SCAN_INITIAL;
-        }
-        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
-            scanFlags |= SCAN_DONT_KILL_APP;
-        }
-        if (instantApp) {
-            scanFlags |= SCAN_AS_INSTANT_APP;
-        }
-        if (fullApp) {
-            scanFlags |= SCAN_AS_FULL_APP;
-        }
-        if (virtualPreload) {
-            scanFlags |= SCAN_AS_VIRTUAL_PRELOAD;
-        }
-
-        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
-
-        // Validity check
-        if (instantApp && onExternal) {
-            Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal);
-            throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID);
-        }
-
-        // Retrieve PackageSettings and parse package
-        @ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY
-                | ParsingPackageUtils.PARSE_ENFORCE_CODE
-                | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0);
-
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
-        final ParsedPackage parsedPackage;
-        try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
-            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
-            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
-        } catch (PackageManagerException e) {
-            throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-
-        // Instant apps have several additional install-time checks.
-        if (instantApp) {
-            if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
-                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
-                                + " does not target at least O");
-                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
-                        "Instant app package must target at least O");
-            }
-            if (parsedPackage.getSharedUserId() != null) {
-                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
-                        + " may not declare sharedUserId.");
-                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
-                        "Instant app package may not declare a sharedUserId");
-            }
-        }
-
-        if (parsedPackage.isStaticSharedLibrary()) {
-            // Static shared libraries have synthetic package names
-            renameStaticSharedLibraryPackage(parsedPackage);
-
-            // No static shared libs on external storage
-            if (onExternal) {
-                Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
-                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
-                        "Packages declaring static-shared libs cannot be updated");
-            }
-        }
-
-        String pkgName = res.name = parsedPackage.getPackageName();
-        if (parsedPackage.isTestOnly()) {
-            if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
-                throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
-            }
-        }
-
-        // either use what we've been given or parse directly from the APK
-        if (args.signingDetails != SigningDetails.UNKNOWN) {
-            parsedPackage.setSigningDetails(args.signingDetails);
-        } else {
-            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-            final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
-                    input, parsedPackage, false /*skipVerify*/);
-            if (result.isError()) {
-                throw new PrepareFailure("Failed collect during installPackageLI",
-                        result.getException());
-            }
-            parsedPackage.setSigningDetails(result.getResult());
-        }
-
-        if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion()
-                < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
-            Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
-                    + " is not signed with at least APK Signature Scheme v2");
-            throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
-                    "Instant app package must be signed with APK Signature Scheme v2 or greater");
-        }
-
-        boolean systemApp = false;
-        boolean replace = false;
-        synchronized (mLock) {
-            // Check if installing already existing package
-            if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
-                String oldName = mSettings.getRenamedPackageLPr(pkgName);
-                if (parsedPackage.getOriginalPackages().contains(oldName)
-                        && mPackages.containsKey(oldName)) {
-                    // This package is derived from an original package,
-                    // and this device has been updating from that original
-                    // name.  We must continue using the original name, so
-                    // rename the new package here.
-                    parsedPackage.setPackageName(oldName);
-                    pkgName = parsedPackage.getPackageName();
-                    replace = true;
-                    if (DEBUG_INSTALL) {
-                        Slog.d(TAG, "Replacing existing renamed package: oldName="
-                                + oldName + " pkgName=" + pkgName);
-                    }
-                } else if (mPackages.containsKey(pkgName)) {
-                    // This package, under its official name, already exists
-                    // on the device; we should replace it.
-                    replace = true;
-                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
-                }
-
-                if (replace) {
-                    // Prevent apps opting out from runtime permissions
-                    AndroidPackage oldPackage = mPackages.get(pkgName);
-                    final int oldTargetSdk = oldPackage.getTargetSdkVersion();
-                    final int newTargetSdk = parsedPackage.getTargetSdkVersion();
-                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
-                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
-                        throw new PrepareFailure(
-                                PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
-                                "Package " + parsedPackage.getPackageName()
-                                        + " new target SDK " + newTargetSdk
-                                        + " doesn't support runtime permissions but the old"
-                                        + " target SDK " + oldTargetSdk + " does.");
-                    }
-                    // Prevent persistent apps from being updated
-                    if (oldPackage.isPersistent()
-                            && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
-                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
-                                "Package " + oldPackage.getPackageName() + " is a persistent app. "
-                                        + "Persistent apps are not updateable.");
-                    }
-                }
-            }
-
-            PackageSetting ps = mSettings.getPackageLPr(pkgName);
-            if (ps != null) {
-                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
-
-                // Static shared libs have same package with different versions where
-                // we internally use a synthetic package name to allow multiple versions
-                // of the same package, therefore we need to compare signatures against
-                // the package setting for the latest library version.
-                PackageSetting signatureCheckPs = ps;
-                if (parsedPackage.isStaticSharedLibrary()) {
-                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage);
-                    if (libraryInfo != null) {
-                        signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
-                    }
-                }
-
-                // Quick validity check that we're signed correctly if updating;
-                // we'll check this again later when scanning, but we want to
-                // bail early here before tripping over redefined permissions.
-                final KeySetManagerService ksms = mSettings.getKeySetManagerService();
-                if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
-                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
-                        throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
-                                + parsedPackage.getPackageName() + " upgrade keys do not match the "
-                                + "previously installed version");
-                    }
-                } else {
-                    try {
-                        final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage);
-                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(
-                                parsedPackage);
-                        // We don't care about disabledPkgSetting on install for now.
-                        final boolean compatMatch = verifySignatures(signatureCheckPs, null,
-                                parsedPackage.getSigningDetails(), compareCompat, compareRecover,
-                                isRollback);
-                        // The new KeySets will be re-added later in the scanning process.
-                        if (compatMatch) {
-                            synchronized (mLock) {
-                                ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
-                            }
-                        }
-                    } catch (PackageManagerException e) {
-                        throw new PrepareFailure(e.error, e.getMessage());
-                    }
-                }
-
-                if (ps.pkg != null) {
-                    systemApp = ps.pkg.isSystem();
-                }
-                res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
-            }
-
-            final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
-            for (int groupNum = 0; groupNum < numGroups; groupNum++) {
-                final ParsedPermissionGroup group =
-                        parsedPackage.getPermissionGroups().get(groupNum);
-                final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(group.getName(), 0);
-
-                if (sourceGroup != null
-                        && cannotInstallWithBadPermissionGroups(parsedPackage)) {
-                    final String sourcePackageName = sourceGroup.packageName;
-
-                    if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName))
-                            && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
-                            scanFlags)) {
-                        EventLog.writeEvent(0x534e4554, "146211400", -1,
-                                parsedPackage.getPackageName());
-
-                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP,
-                                "Package "
-                                        + parsedPackage.getPackageName()
-                                        + " attempting to redeclare permission group "
-                                        + group.getName() + " already owned by "
-                                        + sourcePackageName);
-                    }
-                }
-            }
-
-           // TODO: Move logic for checking permission compatibility into PermissionManagerService
-            final int N = ArrayUtils.size(parsedPackage.getPermissions());
-            for (int i = N - 1; i >= 0; i--) {
-                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
-                final Permission bp = mPermissionManager.getPermissionTEMP(perm.getName());
-
-                // Don't allow anyone but the system to define ephemeral permissions.
-                if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
-                        && !systemApp) {
-                    Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
-                            + " attempting to delcare ephemeral permission "
-                            + perm.getName() + "; Removing ephemeral.");
-                    perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT);
-                }
-
-                // Check whether the newly-scanned package wants to define an already-defined perm
-                if (bp != null) {
-                    final String sourcePackageName = bp.getPackageName();
-
-                    if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
-                            scanFlags)) {
-                        // If the owning package is the system itself, we log but allow
-                        // install to proceed; we fail the install on all other permission
-                        // redefinitions.
-                        if (!sourcePackageName.equals("android")) {
-                            throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
-                                    + parsedPackage.getPackageName()
-                                    + " attempting to redeclare permission "
-                                    + perm.getName() + " already owned by "
-                                    + sourcePackageName)
-                                    .conflictsWithExistingPermission(perm.getName(),
-                                            sourcePackageName);
-                        } else {
-                            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
-                                    + " attempting to redeclare system permission "
-                                    + perm.getName() + "; ignoring new declaration");
-                            parsedPackage.removePermission(i);
-                        }
-                    } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
-                        // Prevent apps to change protection level to dangerous from any other
-                        // type as this would allow a privilege escalation where an app adds a
-                        // normal/signature permission in other app's group and later redefines
-                        // it as dangerous leading to the group auto-grant.
-                        if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE)
-                                == PermissionInfo.PROTECTION_DANGEROUS) {
-                            if (bp != null && !bp.isRuntime()) {
-                                Slog.w(TAG, "Package " + parsedPackage.getPackageName()
-                                        + " trying to change a non-runtime permission "
-                                        + perm.getName()
-                                        + " to runtime; keeping old protection level");
-                                perm.setProtectionLevel(bp.getProtectionLevel());
-                            }
-                        }
-                    }
-                }
-
-                if (perm.getGroup() != null
-                        && cannotInstallWithBadPermissionGroups(parsedPackage)) {
-                    boolean isPermGroupDefinedByPackage = false;
-                    for (int groupNum = 0; groupNum < numGroups; groupNum++) {
-                        if (parsedPackage.getPermissionGroups().get(groupNum).getName()
-                                .equals(perm.getGroup())) {
-                            isPermGroupDefinedByPackage = true;
-                            break;
-                        }
-                    }
-
-                    if (!isPermGroupDefinedByPackage) {
-                        final PermissionGroupInfo sourceGroup =
-                                getPermissionGroupInfo(perm.getGroup(), 0);
-
-                        if (sourceGroup == null) {
-                            EventLog.writeEvent(0x534e4554, "146211400", -1,
-                                    parsedPackage.getPackageName());
-
-                            throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
-                                    "Package "
-                                            + parsedPackage.getPackageName()
-                                            + " attempting to declare permission "
-                                            + perm.getName() + " in non-existing group "
-                                            + perm.getGroup());
-                        } else {
-                            String groupSourcePackageName = sourceGroup.packageName;
-
-                            if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName)
-                                    && !doesSignatureMatchForPermissions(groupSourcePackageName,
-                                    parsedPackage, scanFlags)) {
-                                EventLog.writeEvent(0x534e4554, "146211400", -1,
-                                        parsedPackage.getPackageName());
-
-                                throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
-                                        "Package "
-                                                + parsedPackage.getPackageName()
-                                                + " attempting to declare permission "
-                                                + perm.getName() + " in group "
-                                                + perm.getGroup() + " owned by package "
-                                                + groupSourcePackageName
-                                                + " with incompatible certificate");
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        if (systemApp) {
-            if (onExternal) {
-                // Abort update; system app can't be replaced with app on sdcard
-                throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
-                        "Cannot install updates to system apps on sdcard");
-            } else if (instantApp) {
-                // Abort update; system app can't be replaced with an instant app
-                throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID,
-                        "Cannot update a system app with an instant app");
-            }
-        }
-
-        if (args.move != null) {
-            // We did an in-place move, so dex is ready to roll
-            scanFlags |= SCAN_NO_DEX;
-            scanFlags |= SCAN_MOVE;
-
-            synchronized (mLock) {
-                final PackageSetting ps = mSettings.getPackageLPr(pkgName);
-                if (ps == null) {
-                    res.setError(INSTALL_FAILED_INTERNAL_ERROR,
-                            "Missing settings for moved package " + pkgName);
-                }
-
-                // We moved the entire application as-is, so bring over the
-                // previously derived ABI information.
-                parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
-                        .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
-            }
-
-        } else {
-            // Enable SCAN_NO_DEX flag to skip dexopt at a later stage
-            scanFlags |= SCAN_NO_DEX;
-
-            try {
-                PackageSetting pkgSetting;
-                synchronized (mLock) {
-                    pkgSetting = mSettings.getPackageLPr(pkgName);
-                }
-                boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null
-                        && pkgSetting.getPkgState().isUpdatedSystemApp();
-                final String abiOverride = deriveAbiOverride(args.abiOverride);
-                AndroidPackage oldPackage = mPackages.get(pkgName);
-                boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem();
-                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
-                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
-                        isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
-                        abiOverride, mAppLib32InstallDir);
-                derivedAbi.first.applyTo(parsedPackage);
-                derivedAbi.second.applyTo(parsedPackage);
-            } catch (PackageManagerException pme) {
-                Slog.e(TAG, "Error deriving application ABI", pme);
-                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
-                        "Error deriving application ABI: " + pme.getMessage());
-            }
-        }
-
-        if (!args.doRename(res.returnCode, parsedPackage)) {
-            throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
-        }
-
-        try {
-            setUpFsVerityIfPossible(parsedPackage);
-        } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
-            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
-                    "Failed to set up verity: " + e);
-        }
-
-        final PackageFreezer freezer =
-                freezePackageForInstall(pkgName, installFlags, "installPackageLI");
-        boolean shouldCloseFreezerBeforeReturn = true;
-        try {
-            final AndroidPackage existingPackage;
-            String renamedPackage = null;
-            boolean sysPkg = false;
-            int targetScanFlags = scanFlags;
-            int targetParseFlags = parseFlags;
-            final PackageSetting ps;
-            final PackageSetting disabledPs;
-            if (replace) {
-                if (parsedPackage.isStaticSharedLibrary()) {
-                    // Static libs have a synthetic package name containing the version
-                    // and cannot be updated as an update would get a new package name,
-                    // unless this is installed from adb which is useful for development.
-                    AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName());
-                    if (existingPkg != null
-                            && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) {
-                        throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
-                                "Packages declaring "
-                                        + "static-shared libs cannot be updated");
-                    }
-                }
-
-                final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
-
-                final AndroidPackage oldPackage;
-                final String pkgName11 = parsedPackage.getPackageName();
-                final int[] allUsers;
-                final int[] installedUsers;
-                final int[] uninstalledUsers;
-
-                synchronized (mLock) {
-                    oldPackage = mPackages.get(pkgName11);
-                    existingPackage = oldPackage;
-                    if (DEBUG_INSTALL) {
-                        Slog.d(TAG,
-                                "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
-                    }
-
-                    ps = mSettings.getPackageLPr(pkgName11);
-                    disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
-
-                    // verify signatures are valid
-                    final KeySetManagerService ksms = mSettings.getKeySetManagerService();
-                    if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
-                        if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
-                            throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                                    "New package not signed by keys specified by upgrade-keysets: "
-                                            + pkgName11);
-                        }
-                    } else {
-                        SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
-                        SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
-                        // default to original signature matching
-                        if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
-                                SigningDetails.CertCapabilities.INSTALLED_DATA)
-                                && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
-                                SigningDetails.CertCapabilities.ROLLBACK)) {
-                            // Allow the update to proceed if this is a rollback and the parsed
-                            // package's current signing key is the current signer or in the lineage
-                            // of the old package; this allows a rollback to a previously installed
-                            // version after an app's signing key has been rotated without requiring
-                            // the rollback capability on the previous signing key.
-                            if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
-                                    parsedPkgSigningDetails)) {
-                                throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                                        "New package has a different signature: " + pkgName11);
-                            }
-                        }
-                    }
-
-                    // don't allow a system upgrade unless the upgrade hash matches
-                    if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
-                        final byte[] digestBytes;
-                        try {
-                            final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                            updateDigest(digest, new File(parsedPackage.getBaseApkPath()));
-                            if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
-                                for (String path : parsedPackage.getSplitCodePaths()) {
-                                    updateDigest(digest, new File(path));
-                                }
-                            }
-                            digestBytes = digest.digest();
-                        } catch (NoSuchAlgorithmException | IOException e) {
-                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
-                                    "Could not compute hash: " + pkgName11);
-                        }
-                        if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
-                            throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
-                                    "New package fails restrict-update check: " + pkgName11);
-                        }
-                        // retain upgrade restriction
-                        parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
-                    }
-
-                    // Check for shared user id changes
-                    String invalidPackageName = null;
-                    if (!Objects.equals(oldPackage.getSharedUserId(),
-                            parsedPackage.getSharedUserId())) {
-                        invalidPackageName = parsedPackage.getPackageName();
-                    }
-
-                    if (invalidPackageName != null) {
-                        throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
-                                "Package " + invalidPackageName + " tried to change user "
-                                        + oldPackage.getSharedUserId());
-                    }
-
-                    // In case of rollback, remember per-user/profile install state
-                    allUsers = mUserManager.getUserIds();
-                    installedUsers = ps.queryInstalledUsers(allUsers, true);
-                    uninstalledUsers = ps.queryInstalledUsers(allUsers, false);
-
-
-                    // don't allow an upgrade from full to ephemeral
-                    if (isInstantApp) {
-                        if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) {
-                            for (int currentUser : allUsers) {
-                                if (!ps.getInstantApp(currentUser)) {
-                                    // can't downgrade from full to instant
-                                    Slog.w(TAG,
-                                            "Can't replace full app with instant app: " + pkgName11
-                                                    + " for user: " + currentUser);
-                                    throw new PrepareFailure(
-                                            PackageManager.INSTALL_FAILED_SESSION_INVALID);
-                                }
-                            }
-                        } else if (!ps.getInstantApp(args.user.getIdentifier())) {
-                            // can't downgrade from full to instant
-                            Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11
-                                    + " for user: " + args.user.getIdentifier());
-                            throw new PrepareFailure(
-                                    PackageManager.INSTALL_FAILED_SESSION_INVALID);
-                        }
-                    }
-                }
-
-                // Update what is removed
-                res.removedInfo = new PackageRemovedInfo(this);
-                res.removedInfo.uid = oldPackage.getUid();
-                res.removedInfo.removedPackage = oldPackage.getPackageName();
-                res.removedInfo.installerPackageName = ps.installSource.installerPackageName;
-                res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null;
-                res.removedInfo.isUpdate = true;
-                res.removedInfo.origUsers = installedUsers;
-                res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
-                for (int i = 0; i < installedUsers.length; i++) {
-                    final int userId = installedUsers[i];
-                    res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
-                }
-                res.removedInfo.uninstallReasons = new SparseArray<>(uninstalledUsers.length);
-                for (int i = 0; i < uninstalledUsers.length; i++) {
-                    final int userId = uninstalledUsers[i];
-                    res.removedInfo.uninstallReasons.put(userId, ps.getUninstallReason(userId));
-                }
-
-                sysPkg = oldPackage.isSystem();
-                if (sysPkg) {
-                    // Set the system/privileged/oem/vendor/product flags as needed
-                    final boolean privileged = oldPackage.isPrivileged();
-                    final boolean oem = oldPackage.isOem();
-                    final boolean vendor = oldPackage.isVendor();
-                    final boolean product = oldPackage.isProduct();
-                    final boolean odm = oldPackage.isOdm();
-                    final boolean systemExt = oldPackage.isSystemExt();
-                    final @ParseFlags int systemParseFlags = parseFlags;
-                    final @ScanFlags int systemScanFlags = scanFlags
-                            | SCAN_AS_SYSTEM
-                            | (privileged ? SCAN_AS_PRIVILEGED : 0)
-                            | (oem ? SCAN_AS_OEM : 0)
-                            | (vendor ? SCAN_AS_VENDOR : 0)
-                            | (product ? SCAN_AS_PRODUCT : 0)
-                            | (odm ? SCAN_AS_ODM : 0)
-                            | (systemExt ? SCAN_AS_SYSTEM_EXT : 0);
-
-                    if (DEBUG_INSTALL) {
-                        Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
-                                + ", old=" + oldPackage);
-                    }
-                    res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    targetParseFlags = systemParseFlags;
-                    targetScanFlags = systemScanFlags;
-                } else { // non system replace
-                    replace = true;
-                    if (DEBUG_INSTALL) {
-                        Slog.d(TAG,
-                                "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
-                                        + oldPackage);
-                    }
-                }
-            } else { // new package install
-                ps = null;
-                disabledPs = null;
-                replace = false;
-                existingPackage = null;
-                // Remember this for later, in case we need to rollback this install
-                String pkgName1 = parsedPackage.getPackageName();
-
-                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
-
-                // TODO(patb): MOVE TO RECONCILE
-                synchronized (mLock) {
-                    renamedPackage = mSettings.getRenamedPackageLPr(pkgName1);
-                    if (renamedPackage != null) {
-                        // A package with the same name is already installed, though
-                        // it has been renamed to an older name.  The package we
-                        // are trying to install should be installed as an update to
-                        // the existing one, but that has not been requested, so bail.
-                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
-                                "Attempt to re-install " + pkgName1
-                                        + " without first uninstalling package running as "
-                                        + renamedPackage);
-                    }
-                    if (mPackages.containsKey(pkgName1)) {
-                        // Don't allow installation over an existing package with the same name.
-                        throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS,
-                                "Attempt to re-install " + pkgName1
-                                        + " without first uninstalling.");
-                    }
-                }
-            }
-            // we're passing the freezer back to be closed in a later phase of install
-            shouldCloseFreezerBeforeReturn = false;
-
-            return new PrepareResult(replace, targetScanFlags, targetParseFlags,
-                    existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg,
-                    ps, disabledPs);
-        } finally {
-            res.freezer = freezer;
-            if (shouldCloseFreezerBeforeReturn) {
-                freezer.close();
-            }
-        }
-    }
-
-    /**
-     * Set up fs-verity for the given package if possible.  This requires a feature flag of system
-     * property to be enabled only if the kernel supports fs-verity.
-     *
-     * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
-     * kernel patches). In normal mode, all file format can be supported.
-     */
-    private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
-            PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
-        final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
-        final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
-        if (!standardMode && !legacyMode) {
-            return;
-        }
-
-        if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion()
-                < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) {
-            return;
-        }
-
-        // Collect files we care for fs-verity setup.
-        ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
-        if (legacyMode) {
-            synchronized (mLock) {
-                final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
-                if (ps != null && ps.isPrivileged()) {
-                    fsverityCandidates.put(pkg.getBaseApkPath(), null);
-                    if (pkg.getSplitCodePaths() != null) {
-                        for (String splitPath : pkg.getSplitCodePaths()) {
-                            fsverityCandidates.put(splitPath, null);
-                        }
-                    }
-                }
-            }
-        } else {
-            // NB: These files will become only accessible if the signing key is loaded in kernel's
-            // .fs-verity keyring.
-            fsverityCandidates.put(pkg.getBaseApkPath(),
-                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath()));
-
-            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
-                    pkg.getBaseApkPath());
-            if (new File(dmPath).exists()) {
-                fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
-            }
-
-            if (pkg.getSplitCodePaths() != null) {
-                for (String path : pkg.getSplitCodePaths()) {
-                    fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
-
-                    final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
-                    if (new File(splitDmPath).exists()) {
-                        fsverityCandidates.put(splitDmPath,
-                                VerityUtils.getFsveritySignatureFilePath(splitDmPath));
-                    }
-                }
-            }
-        }
-
-        for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
-            final String filePath = entry.getKey();
-            final String signaturePath = entry.getValue();
-
-            if (!legacyMode) {
-                // fs-verity is optional for now.  Only set up if signature is provided.
-                if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
-                    try {
-                        VerityUtils.setUpFsverity(filePath, signaturePath);
-                    } catch (IOException e) {
-                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
-                                "Failed to enable fs-verity: " + e);
-                    }
-                }
-                continue;
-            }
-
-            // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
-            final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
-            if (result.isOk()) {
-                if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
-                final FileDescriptor fd = result.getUnownedFileDescriptor();
-                try {
-                    final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
-                    try {
-                        // A file may already have fs-verity, e.g. when reused during a split
-                        // install. If the measurement succeeds, no need to attempt to set up.
-                        mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
-                    } catch (InstallerException e) {
-                        mInstaller.installApkVerity(filePath, fd, result.getContentSize());
-                        mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
-                    }
-                } finally {
-                    IoUtils.closeQuietly(fd);
-                }
-            } else if (result.isFailed()) {
-                throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
-                        "Failed to generate verity");
-            }
-        }
-    }
-
-    private static boolean isExternal(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
     private static boolean isSystemApp(PackageSetting ps) {
@@ -21196,7 +17494,7 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
-    private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
+    VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
         if (pkg.isExternalStorage()) {
             if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return mSettings.getExternalVersion();
@@ -21436,12 +17734,8 @@
 
         // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
         // uninstall for device owner provisioning.
-        if (checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
-                == PERMISSION_GRANTED) {
-            return true;
-        }
-
-        return false;
+        return checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+                == PERMISSION_GRANTED;
     }
 
     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
@@ -21599,7 +17893,7 @@
                 }
             }
 
-            info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
+            info.mOrigUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
 
             if (isUpdatedSystemApp(uninstalledPs)
                     && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
@@ -21624,15 +17918,15 @@
             try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser,
                     deleteFlags, "deletePackageX")) {
                 res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers,
-                        deleteFlags | PackageManager.DELETE_CHATTY, info, true, null);
+                        deleteFlags | PackageManager.DELETE_CHATTY, info, true);
             }
             synchronized (mLock) {
                 if (res) {
                     if (pkg != null) {
                         mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs,
-                                info.removedUsers);
+                                info.mRemovedUsers);
                     }
-                    updateSequenceNumberLP(uninstalledPs, info.removedUsers);
+                    updateSequenceNumberLP(uninstalledPs, info.mRemovedUsers);
                     updateInstantAppInstallerLocked(packageName);
                 }
             }
@@ -21649,8 +17943,8 @@
         // Delete the resources here after sending the broadcast to let
         // other processes clean up before deleting resources.
         synchronized (mInstallLock) {
-            if (info.args != null) {
-                info.args.doPostDeleteLI(true);
+            if (info.mArgs != null) {
+                info.mArgs.doPostDeleteLI(true);
             }
 
             boolean reEnableStub = false;
@@ -21702,135 +17996,6 @@
         return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
     }
 
-    static class PackageRemovedInfo {
-        final PackageSender packageSender;
-        String removedPackage;
-        String installerPackageName;
-        int uid = -1;
-        int removedAppId = -1;
-        int[] origUsers;
-        int[] removedUsers = null;
-        int[] broadcastUsers = null;
-        int[] instantUserIds = null;
-        SparseArray<Integer> installReasons;
-        SparseArray<Integer> uninstallReasons;
-        boolean isRemovedPackageSystemUpdate = false;
-        boolean isUpdate;
-        boolean dataRemoved;
-        boolean removedForAllUsers;
-        boolean isStaticSharedLib;
-        // a two dimensional array mapping userId to the set of appIds that can receive notice
-        // of package changes
-        SparseArray<int[]> broadcastAllowList;
-        // Clean up resources deleted packages.
-        InstallArgs args = null;
-
-        PackageRemovedInfo(PackageSender packageSender) {
-            this.packageSender = packageSender;
-        }
-
-        void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
-            sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
-        }
-
-        void sendSystemPackageUpdatedBroadcasts() {
-            if (isRemovedPackageSystemUpdate) {
-                sendSystemPackageUpdatedBroadcastsInternal();
-            }
-        }
-
-        private void sendSystemPackageUpdatedBroadcastsInternal() {
-            Bundle extras = new Bundle(2);
-            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, broadcastAllowList, null);
-            packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
-                    extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
-            packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
-                    removedPackage, null, null, null, null /* broadcastAllowList */,
-                    getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
-            if (installerPackageName != null) {
-                packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
-                        removedPackage, extras, 0 /*flags*/,
-                        installerPackageName, null, null, null, null /* broadcastAllowList */,
-                        null);
-                packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
-                        removedPackage, extras, 0 /*flags*/,
-                        installerPackageName, null, null, null, null /* broadcastAllowList */,
-                        null);
-            }
-        }
-
-        private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
-            // Don't send static shared library removal broadcasts as these
-            // libs are visible only the the apps that depend on them an one
-            // cannot remove the library if it has a dependency.
-            if (isStaticSharedLib) {
-                return;
-            }
-            Bundle extras = new Bundle(2);
-            final int removedUid = removedAppId >= 0  ? removedAppId : uid;
-            extras.putInt(Intent.EXTRA_UID, removedUid);
-            extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
-            extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
-            extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
-            if (isUpdate || isRemovedPackageSystemUpdate) {
-                extras.putBoolean(Intent.EXTRA_REPLACING, true);
-            }
-            extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
-            if (removedPackage != null) {
-                packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
-                        removedPackage, extras, 0, null /*targetPackage*/, null,
-                        broadcastUsers, instantUserIds, broadcastAllowList, null);
-                if (installerPackageName != null) {
-                    packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
-                            removedPackage, extras, 0 /*flags*/,
-                            installerPackageName, null, broadcastUsers, instantUserIds, null, null);
-                }
-                packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
-                        removedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
-                        null /*finishedReceiver*/, broadcastUsers, instantUserIds,
-                        broadcastAllowList, null /*bOptions*/);
-                if (dataRemoved && !isRemovedPackageSystemUpdate) {
-                    packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
-                            removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
-                            null, broadcastUsers, instantUserIds, broadcastAllowList, null);
-                    packageSender.notifyPackageRemoved(removedPackage, removedUid);
-                }
-            }
-            if (removedAppId >= 0) {
-                // If a system app's updates are uninstalled the UID is not actually removed. Some
-                // services need to know the package name affected.
-                if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
-                    extras.putString(Intent.EXTRA_PACKAGE_NAME, removedPackage);
-                }
-
-                packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
-                        null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
-                        null, null, broadcastUsers, instantUserIds, broadcastAllowList, null);
-            }
-        }
-
-        void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
-            removedUsers = userIds;
-            if (removedUsers == null) {
-                broadcastUsers = null;
-                return;
-            }
-
-            broadcastUsers = EMPTY_INT_ARRAY;
-            instantUserIds = EMPTY_INT_ARRAY;
-            for (int i = userIds.length - 1; i >= 0; --i) {
-                final int userId = userIds[i];
-                if (deletedPackageSetting.getInstantApp(userId)) {
-                    instantUserIds = ArrayUtils.appendInt(instantUserIds, userId);
-                } else {
-                    broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId);
-                }
-            }
-        }
-    }
 
     /*
      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
@@ -21845,9 +18010,9 @@
         // Retrieve object to delete permissions for shared user later on
         final AndroidPackage deletedPkg = deletedPs.pkg;
         if (outInfo != null) {
-            outInfo.removedPackage = packageName;
-            outInfo.installerPackageName = deletedPs.installSource.installerPackageName;
-            outInfo.isStaticSharedLib = deletedPkg != null
+            outInfo.mRemovedPackage = packageName;
+            outInfo.mInstallerPackageName = deletedPs.installSource.installerPackageName;
+            outInfo.mIsStaticSharedLib = deletedPkg != null
                     && deletedPkg.getStaticSharedLibName() != null;
             outInfo.populateUsers(deletedPs == null ? null
                     : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
@@ -21869,7 +18034,7 @@
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
             destroyAppProfilesLIF(resolvedPkg);
             if (outInfo != null) {
-                outInfo.dataRemoved = true;
+                outInfo.mDataRemoved = true;
             }
         }
 
@@ -21886,7 +18051,7 @@
                     mAppsFilter.removePackage(getPackageSetting(packageName));
                     removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
-                        outInfo.removedAppId = removedAppId;
+                        outInfo.mRemovedAppId = removedAppId;
                     }
                     if (!mSettings.isDisabledSystemPackageLPr(packageName)) {
                         // If we don't have a disabled system package to reinstall, the package is
@@ -21912,12 +18077,12 @@
             }
             // make sure to preserve per-user disabled state if this removal was just
             // a downgrade of a system app to the factory package
-            if (outInfo != null && outInfo.origUsers != null) {
+            if (outInfo != null && outInfo.mOrigUsers != null) {
                 if (DEBUG_REMOVE) {
                     Slog.d(TAG, "Propagating install state across downgrade");
                 }
                 for (int userId : allUserHandles) {
-                    final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId);
+                    final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
                     if (DEBUG_REMOVE) {
                         Slog.d(TAG, "    user " + userId + " => " + installed);
                     }
@@ -21968,13 +18133,13 @@
             @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo,
             boolean writeSettings)
             throws SystemDeleteException {
-        final boolean applyUserRestrictions = outInfo != null && (outInfo.origUsers != null);
+        final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null);
         final AndroidPackage deletedPkg = deletedPs.pkg;
         // Confirm if the system package has been updated
         // An updated system app can be deleted. This will also have to restore
         // the system pkg from system partition
         // reader
-        final PackageSetting disabledPs = action.disabledPs;
+        final PackageSetting disabledPs = action.mDisabledPs;
         if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
                 + " disabledPs=" + disabledPs);
         Slog.d(TAG, "Deleting system pkg from data partition");
@@ -21983,7 +18148,7 @@
             if (applyUserRestrictions) {
                 Slog.d(TAG, "Remembering install states:");
                 for (int userId : allUserHandles) {
-                    final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId);
+                    final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId);
                     Slog.d(TAG, "   u=" + userId + " inst=" + finstalled);
                 }
             }
@@ -21991,7 +18156,7 @@
 
         if (outInfo != null) {
             // Delete the updated package
-            outInfo.isRemovedPackageSystemUpdate = true;
+            outInfo.mIsRemovedPackageSystemUpdate = true;
         }
 
         if (disabledPs.versionCode < deletedPs.versionCode) {
@@ -22021,7 +18186,7 @@
         if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
         try {
             installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
-                    outInfo == null ? null : outInfo.origUsers, writeSettings);
+                    outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
                     + e.getMessage());
@@ -22034,8 +18199,8 @@
                 // and re-enable it afterward.
                 final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
                 if (stubPs != null) {
-                    int userId = action.user == null
-                            ? UserHandle.USER_ALL : action.user.getIdentifier();
+                    int userId = action.mUser == null
+                            ? UserHandle.USER_ALL : action.mUser.getIdentifier();
                     if (userId == UserHandle.USER_ALL) {
                         for (int aUserId : allUserHandles) {
                             stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
@@ -22051,7 +18216,7 @@
     /**
      * Installs a package that's already on the system partition.
      */
-    private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
+    private void installPackageFromSystemLIF(@NonNull String codePathString,
             @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
             throws PackageManagerException {
         final File codePath = new File(codePathString);
@@ -22133,7 +18298,6 @@
                 writeSettingsLPrTEMP();
             }
         }
-        return pkg;
     }
 
     private void deleteInstalledPackageLIF(PackageSetting ps,
@@ -22141,8 +18305,8 @@
             PackageRemovedInfo outInfo, boolean writeSettings) {
         synchronized (mLock) {
             if (outInfo != null) {
-                outInfo.uid = ps.appId;
-                outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
+                outInfo.mUid = ps.appId;
+                outInfo.mBroadcastAllowList = mAppsFilter.getVisibilityAllowList(ps,
                         allUserHandles, mSettings.getPackagesLocked());
             }
         }
@@ -22152,10 +18316,10 @@
 
         // Delete application code and resources only for parent packages
         if (deleteCodeAndResources && (outInfo != null)) {
-            outInfo.args = createInstallArgsForExisting(
+            outInfo.mArgs = createInstallArgsForExisting(
                     ps.getPathString(), getAppDexInstructionSets(
                             ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
-            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
+            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs);
         }
     }
 
@@ -22211,23 +18375,6 @@
         return true;
     }
 
-    private static class DeletePackageAction {
-        public final PackageSetting deletingPs;
-        public final PackageSetting disabledPs;
-        public final PackageRemovedInfo outInfo;
-        public final int flags;
-        public final UserHandle user;
-
-        private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
-                PackageRemovedInfo outInfo, int flags, UserHandle user) {
-            this.deletingPs = deletingPs;
-            this.disabledPs = disabledPs;
-            this.outInfo = outInfo;
-            this.flags = flags;
-            this.user = user;
-        }
-    }
-
     /**
      * @return a {@link DeletePackageAction} if the provided package and related state may be
      * deleted, {@code null} otherwise.
@@ -22260,8 +18407,7 @@
      */
     private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
             boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags,
-            PackageRemovedInfo outInfo, boolean writeSettings,
-            ParsedPackage replacingPackage) {
+            PackageRemovedInfo outInfo, boolean writeSettings) {
         final DeletePackageAction action;
         synchronized (mLock) {
             final PackageSetting ps = mSettings.getPackageLPr(packageName);
@@ -22277,7 +18423,7 @@
 
         try {
             executeDeletePackageLIF(action, packageName, deleteCodeAndResources,
-                    allUserHandles, writeSettings, replacingPackage);
+                    allUserHandles, writeSettings);
         } catch (SystemDeleteException e) {
             if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e);
             return false;
@@ -22285,23 +18431,14 @@
         return true;
     }
 
-    private static class SystemDeleteException extends Exception {
-        public final PackageManagerException reason;
-
-        private SystemDeleteException(PackageManagerException reason) {
-            this.reason = reason;
-        }
-    }
-
     /** Deletes a package. Only throws when install of a disabled package fails. */
-    private void executeDeletePackageLIF(DeletePackageAction action,
+    void executeDeletePackageLIF(DeletePackageAction action,
             String packageName, boolean deleteCodeAndResources,
-            @NonNull int[] allUserHandles, boolean writeSettings,
-            ParsedPackage replacingPackage) throws SystemDeleteException {
-        final PackageSetting ps = action.deletingPs;
-        final PackageRemovedInfo outInfo = action.outInfo;
-        final UserHandle user = action.user;
-        final int flags = action.flags;
+            @NonNull int[] allUserHandles, boolean writeSettings) throws SystemDeleteException {
+        final PackageSetting ps = action.mDeletingPs;
+        final PackageRemovedInfo outInfo = action.mRemovedInfo;
+        final UserHandle user = action.mUser;
+        final int flags = action.mFlags;
         final boolean systemApp = isSystemApp(ps);
 
         // We need to get the permission state before package state is (potentially) destroyed.
@@ -22372,7 +18509,7 @@
 
         // If the package removed had SUSPEND_APPS, unset any restrictions that might have been in
         // place for all affected users.
-        int[] affectedUserIds = (outInfo != null) ? outInfo.removedUsers : null;
+        int[] affectedUserIds = (outInfo != null) ? outInfo.mRemovedUsers : null;
         if (affectedUserIds == null) {
             affectedUserIds = resolveUserIds(userId);
         }
@@ -22385,7 +18522,7 @@
 
         // Take a note whether we deleted the package for all users
         if (outInfo != null) {
-            outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
+            outInfo.mRemovedForAllUsers = mPackages.get(ps.name) == null;
         }
     }
 
@@ -22451,14 +18588,14 @@
 
         if (outInfo != null) {
             if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
-                outInfo.dataRemoved = true;
+                outInfo.mDataRemoved = true;
             }
-            outInfo.removedPackage = ps.name;
-            outInfo.installerPackageName = ps.installSource.installerPackageName;
-            outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
-            outInfo.removedAppId = ps.appId;
-            outInfo.removedUsers = userIds;
-            outInfo.broadcastUsers = userIds;
+            outInfo.mRemovedPackage = ps.name;
+            outInfo.mInstallerPackageName = ps.installSource.installerPackageName;
+            outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
+            outInfo.mRemovedAppId = ps.appId;
+            outInfo.mRemovedUsers = userIds;
+            outInfo.mBroadcastUsers = userIds;
         }
     }
 
@@ -22473,7 +18610,7 @@
 
         try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationProfileData")) {
             synchronized (mInstallLock) {
-                clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
+                clearAppProfilesLIF(pkg);
             }
         }
     }
@@ -22972,7 +19109,7 @@
     }
 
     private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName,
-            int installReason, @UserIdInt int userId) {
+            @UserIdInt int userId) {
         // We may also need to apply pending (restored) runtime permission grants
         // within these users.
         mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
@@ -23513,7 +19650,7 @@
         final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
                 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
         final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
-                intent, null, 0, resolveInfos, 0, true, false, false, userId);
+                intent, null, 0, resolveInfos, true, false, false, userId);
         final String packageName = preferredResolveInfo != null
                 && preferredResolveInfo.activityInfo != null
                 ? preferredResolveInfo.activityInfo.packageName : null;
@@ -23756,18 +19893,6 @@
         return packageName;
     }
 
-    @Nullable
-    private String[] ensureSystemPackageNames(@Nullable String[] packageNames) {
-        if (packageNames == null) {
-            return null;
-        }
-        final int packageNamesLength = packageNames.length;
-        for (int i = 0; i < packageNamesLength; i++) {
-            packageNames[i] = ensureSystemPackageName(packageNames[i]);
-        }
-        return ArrayUtils.filterNotNull(packageNames, String[]::new);
-    }
-
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
@@ -24133,7 +20258,7 @@
                     + componentNames);
         Bundle extras = new Bundle(4);
         extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
-        String nameList[] = new String[componentNames.size()];
+        String[] nameList = new String[componentNames.size()];
         componentNames.toArray(nameList);
         extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp);
@@ -24407,11 +20532,7 @@
                                 componentInfo.getComponentName(), userId);
                 if (componentEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) {
                     return componentInfo.isEnabled();
-                } else if (componentEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) {
-                    return false;
-                }
-
-                return true;
+                } else return componentEnabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
             } catch (PackageManager.NameNotFoundException ignored) {
                 return false;
             }
@@ -24851,11 +20972,11 @@
             pw.println("vers,1");
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_VERSION)
-                && packageName == null) {
-            // dump version information for all volumes with installed packages
-            dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+        // reader
+        if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+            if (!checkin) {
+                dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+            }
         }
 
         if (!checkin
@@ -24868,7 +20989,7 @@
             ipw.println("Known Packages:");
             ipw.increaseIndent();
             for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) {
-                final String knownPackage = mPmInternal.knownPackageToString(i);
+                final String knownPackage = PackageManagerInternal.knownPackageToString(i);
                 ipw.print(knownPackage);
                 ipw.println(":");
                 final String[] pkgNames = mPmInternal.getKnownPackageNames(i,
@@ -24886,8 +21007,7 @@
             ipw.decreaseIndent();
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
             final String requiredVerifierPackage = mRequiredVerifierPackage;
             if (!checkin) {
                 if (dumpState.onTitlePrinted()) {
@@ -24908,8 +21028,7 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) {
             final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
             final ComponentName verifierComponent = proxy.getComponentName();
             if (verifierComponent != null) {
@@ -24936,13 +21055,11 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_LIBS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
             dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_FEATURES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
             if (dumpState.onTitlePrinted()) {
                 pw.println();
             }
@@ -24952,7 +21069,12 @@
 
             synchronized (mAvailableFeatures) {
                 for (FeatureInfo feat : mAvailableFeatures.values()) {
-                    if (!checkin) {
+                    if (checkin) {
+                        pw.print("feat,");
+                        pw.print(feat.name);
+                        pw.print(",");
+                        pw.println(feat.version);
+                    } else {
                         pw.print("  ");
                         pw.print(feat.name);
                         if (feat.version > 0) {
@@ -24960,73 +21082,55 @@
                             pw.print(feat.version);
                         }
                         pw.println();
-                    } else {
-                        pw.print("feat,");
-                        pw.print(feat.name);
-                        pw.print(",");
-                        pw.println(feat.version);
                     }
                 }
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PREFERRED)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
             dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
             dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
             dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
             mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
             synchronized (mLock) {
                 mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
             }
@@ -25041,15 +21145,11 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_QUERIES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
             dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SHARED_USERS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
             // This cannot be moved to ComputerEngine since the set of packages in the
             // SharedUserSetting do not have a copy.
             synchronized (mLock) {
@@ -25057,9 +21157,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_CHANGES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
             if (dumpState.onTitlePrinted()) pw.println();
             pw.println("Package Changes:");
             synchronized (mLock) {
@@ -25086,9 +21184,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_FROZEN)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
             // XXX should handle packageName != null by dumping only install data that
             // the given package is involved with.
             if (dumpState.onTitlePrinted()) pw.println();
@@ -25109,9 +21205,7 @@
             ipw.decreaseIndent();
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_VOLUMES)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
             if (dumpState.onTitlePrinted()) pw.println();
 
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
@@ -25130,61 +21224,50 @@
             ipw.decreaseIndent();
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
                 && packageName == null) {
             synchronized (mLock) {
                 mComponentResolver.dumpServicePermissions(pw, dumpState);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_DEXOPT)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
             if (dumpState.onTitlePrinted()) pw.println();
             dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
             if (dumpState.onTitlePrinted()) pw.println();
             dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
-                && packageName == null) {
-            if (!checkin) {
-                if (dumpState.onTitlePrinted()) pw.println();
-                synchronized (mLock) {
-                    mSettings.dumpReadMessagesLPr(pw, dumpState);
-                }
-                pw.println();
-                pw.println("Package warning messages:");
-                dumpCriticalInfo(pw, null);
-            } else {
-                dumpCriticalInfo(pw, "msg,");
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+            if (dumpState.onTitlePrinted()) pw.println();
+            synchronized (mLock) {
+                mSettings.dumpReadMessagesLPr(pw, dumpState);
             }
+            pw.println();
+            pw.println("Package warning messages:");
+            dumpCriticalInfo(pw, null);
+        }
+
+        if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
+            dumpCriticalInfo(pw, "msg,");
         }
 
         // PackageInstaller should be called outside of mPackages lock
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_INSTALLS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
             // XXX should handle packageName != null by dumping only install data that
             // the given package is involved with.
             if (dumpState.onTitlePrinted()) pw.println();
             mInstallerService.dump(new IndentingPrintWriter(pw, "  ", 120));
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_APEX)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
             mApexManager.dump(pw, packageName);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
                 && packageName == null) {
             pw.println();
             pw.println("Per UID read timeouts:");
@@ -25203,9 +21286,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
             pw.println("Snapshot statistics");
             if (!mSnapshotEnabled) {
                 pw.println("  Snapshots disabled");
@@ -25233,9 +21314,9 @@
 
     //TODO: b/111402650
     private void disableSkuSpecificApps() {
-        String apkList[] = mContext.getResources().getStringArray(
+        String[] apkList = mContext.getResources().getStringArray(
                 R.array.config_disableApksUnlessMatchedSku_apk_list);
-        String skuArray[] = mContext.getResources().getStringArray(
+        String[] skuArray = mContext.getResources().getStringArray(
                 R.array.config_disableApkUnlessMatchedSku_skus_list);
         if (ArrayUtils.isEmpty(apkList)) {
            return;
@@ -25334,32 +21415,6 @@
 
     private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
 
-    private static final String SD_ENCRYPTION_ALGORITHM = "AES";
-
-    private boolean mMediaMounted = false;
-
-    static String getEncryptKey() {
-        try {
-            String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
-                    SD_ENCRYPTION_KEYSTORE_NAME);
-            if (sdEncKey == null) {
-                sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128,
-                        SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME);
-                if (sdEncKey == null) {
-                    Slog.e(TAG, "Failed to create encryption keys");
-                    return null;
-                }
-            }
-            return sdEncKey;
-        } catch (NoSuchAlgorithmException nsae) {
-            Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
-            return null;
-        } catch (IOException ioe) {
-            Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe);
-            return null;
-        }
-    }
-
     private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
             ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
         final int size = packages.size();
@@ -25374,8 +21429,8 @@
                 finishedReceiver);
     }
 
-    private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
-            ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+    void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+            ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver) {
         sendResourcesChangedBroadcast(mediaStatus, replacing,
                 pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
     }
@@ -25519,7 +21574,7 @@
                     try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
                             "unloadPrivatePackagesInner")) {
                         if (deletePackageLIF(ps.name, null, false, userIds, deleteFlags, outInfo,
-                                false, null)) {
+                                false)) {
                             unloaded.add(pkg);
                         } else {
                             Slog.w(TAG, "Failed to unload " + ps.getPath());
@@ -25776,7 +21831,7 @@
      * <p>
      * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
      */
-    private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
+    void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
         final PackageSetting ps;
         synchronized (mLock) {
             ps = mSettings.getPackageLPr(pkg.getPackageName());
@@ -25796,6 +21851,10 @@
                 continue;
             }
 
+            // TODO@ashfall check ScanResult.mNeedsNewAppId, and if true instead
+            // of creating app data, migrate / change ownership of existing
+            // data.
+
             if (ps.getInstalled(user.id)) {
                 // TODO: when user data is locked, mark that we're still dirty
                 prepareAppData(batch, pkg, user.id, flags).thenRun(() -> {
@@ -25831,9 +21890,9 @@
         return prepareAppDataLeaf(batch, pkg, userId, flags);
     }
 
-    private @NonNull CompletableFuture<?> prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
+    private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch,
             @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) {
-        return prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
+        prepareAppData(batch, pkg, userId, flags).thenRun(() -> {
             // Note: this code block is executed with the Installer lock
             // already held, since it's invoked as a side-effect of
             // executeBatchLI()
@@ -25886,8 +21945,6 @@
                         } catch (InstallerException e2) {
                             logCriticalInfo(Log.DEBUG, "Recovery failed!");
                         }
-                    } else if (e != null) {
-                        Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
                     }
 
                     // Prepare the application profiles only for upgrades and
@@ -25990,21 +22047,7 @@
     }
 
     public PackageFreezer freezePackage(String packageName, int userId, String killReason) {
-        return new PackageFreezer(packageName, userId, killReason);
-    }
-
-    public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
-            String killReason) {
-        return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason);
-    }
-
-    public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
-            String killReason) {
-        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
-            return new PackageFreezer();
-        } else {
-            return freezePackage(packageName, userId, killReason);
-        }
+        return new PackageFreezer(packageName, userId, killReason, this);
     }
 
     public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags,
@@ -26015,74 +22058,13 @@
     public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags,
             String killReason) {
         if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) {
-            return new PackageFreezer();
+            return new PackageFreezer(this);
         } else {
             return freezePackage(packageName, userId, killReason);
         }
     }
 
     /**
-     * Class that freezes and kills the given package upon creation, and
-     * unfreezes it upon closing. This is typically used when doing surgery on
-     * app code/data to prevent the app from running while you're working.
-     */
-    private class PackageFreezer implements AutoCloseable {
-        private final String mPackageName;
-
-        private final boolean mWeFroze;
-
-        private final AtomicBoolean mClosed = new AtomicBoolean();
-        private final CloseGuard mCloseGuard = CloseGuard.get();
-
-        /**
-         * Create and return a stub freezer that doesn't actually do anything,
-         * typically used when someone requested
-         * {@link PackageManager#INSTALL_DONT_KILL_APP} or
-         * {@link PackageManager#DELETE_DONT_KILL_APP}.
-         */
-        public PackageFreezer() {
-            mPackageName = null;
-            mWeFroze = false;
-            mCloseGuard.open("close");
-        }
-
-        public PackageFreezer(String packageName, int userId, String killReason) {
-            synchronized (mLock) {
-                mPackageName = packageName;
-                mWeFroze = mFrozenPackages.add(mPackageName);
-
-                final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
-                if (ps != null) {
-                    killApplication(ps.name, ps.appId, userId, killReason);
-                }
-            }
-            mCloseGuard.open("close");
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                mCloseGuard.warnIfOpen();
-                close();
-            } finally {
-                super.finalize();
-            }
-        }
-
-        @Override
-        public void close() {
-            mCloseGuard.close();
-            if (mClosed.compareAndSet(false, true)) {
-                synchronized (mLock) {
-                    if (mWeFroze) {
-                        mFrozenPackages.remove(mPackageName);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
      * Verify that given package is currently frozen.
      */
     private void checkPackageFrozen(String packageName) {
@@ -26324,23 +22306,14 @@
 
         installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
 
-        final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
         final ParseResult<PackageLite> ret = ApkLiteParseUtils.parsePackageLite(input,
-                new File(origin.resolvedPath), /* flags */ 0);
+                new File(origin.mResolvedPath), /* flags */ 0);
         final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
-                installSource, volumeUuid, user, packageAbiOverride, lite);
-        params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
-        msg.obj = params;
-
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage",
-                System.identityHashCode(msg.obj));
-        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                System.identityHashCode(msg.obj));
-
-        mHandler.sendMessage(msg);
+                installSource, volumeUuid, user, packageAbiOverride, lite, this);
+        params.movePackage();
     }
 
     /**
@@ -26356,7 +22329,7 @@
             return;
         }
 
-        final StorageManager storage = mInjector.getSystemService(StorageManager.class);;
+        final StorageManager storage = mInjector.getSystemService(StorageManager.class);
         VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage());
 
@@ -26546,7 +22519,7 @@
     }
 
     boolean readPermissionStateForUser(@UserIdInt int userId) {
-        synchronized (mPackages) {
+        synchronized (mLock) {
             mPermissionManager.writeLegacyPermissionStateTEMP();
             mSettings.readPermissionStateForUserSyncLPr(userId);
             mPermissionManager.readLegacyPermissionStateTEMP();
@@ -26606,11 +22579,7 @@
                 Binder.restoreCallingIdentity(token);
             }
             final boolean b;
-            if (userInfo != null && userInfo.isManagedProfile()) {
-                b = true;
-            } else {
-                b = false;
-            }
+            b = userInfo != null && userInfo.isManagedProfile();
             mUserNeedsBadging.put(userId, b);
             return b;
         }
@@ -26622,7 +22591,7 @@
         if (packageName == null || alias == null) {
             return null;
         }
-        synchronized(mLock) {
+        synchronized (mLock) {
             final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
                     || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
@@ -26669,7 +22638,7 @@
         if (packageName == null || ks == null) {
             return false;
         }
-        synchronized(mLock) {
+        synchronized (mLock) {
             final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
                     || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
@@ -26727,7 +22696,7 @@
         }
     }
 
-    private Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
+    Pair<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
             long requiredInstalledVersionCode, int installFlags) {
         if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
             return verifyReplacingVersionCodeForApex(
@@ -26832,12 +22801,12 @@
         if (after.getLongVersionCode() < before.getLongVersionCode()) {
             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                     "Update version code " + after.versionCode + " is older than current "
-                    + before.getLongVersionCode());
+                            + before.getLongVersionCode());
         } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
             if (after.baseRevisionCode < before.getBaseRevisionCode()) {
                 throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                         "Update base revision code " + after.baseRevisionCode
-                        + " is older than current " + before.getBaseRevisionCode());
+                                + " is older than current " + before.getBaseRevisionCode());
             }
 
             if (!ArrayUtils.isEmpty(after.splitNames)) {
@@ -26848,8 +22817,9 @@
                         if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
                             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                                     "Update split " + splitName + " revision code "
-                                    + after.splitRevisionCodes[i] + " is older than current "
-                                    + before.getSplitRevisionCodes()[j]);
+                                            + after.splitRevisionCodes[i]
+                                            + " is older than current "
+                                            + before.getSplitRevisionCodes()[j]);
                         }
                     }
                 }
@@ -27068,7 +23038,7 @@
             boolean[] results = new boolean[packageNames.length];
             for (int i = results.length - 1; i >= 0; --i) {
                 ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser);
-                results[i] = appInfo == null ? false : appInfo.isAudioPlaybackCaptureAllowed();
+                results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
             }
             return results;
         }
@@ -27287,7 +23257,7 @@
         @Override
         public @Nullable
         String getDisabledSystemPackageName(@NonNull String packageName) {
-            PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage(
+            PackageSetting disabledPkgSetting = getDisabledSystemPackage(
                     packageName);
             AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
             return disabledPkg == null ? null : disabledPkg.getPackageName();
@@ -27435,7 +23405,7 @@
         public boolean isPackageSuspended(String packageName, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                return (ps != null) ? ps.getSuspended(userId) : false;
+                return ps != null && ps.getSuspended(userId);
             }
         }
 
@@ -27551,6 +23521,13 @@
         }
 
         @Override
+        public List<ResolveInfo> queryIntentReceivers(Intent intent,
+                String resolvedType, int flags, int filterCallingUid, int userId) {
+            return PackageManagerService.this.queryIntentReceiversInternal(intent, resolvedType,
+                    flags, userId, filterCallingUid);
+        }
+
+        @Override
         public List<ResolveInfo> queryIntentServices(
                 Intent intent, int flags, int callingUid, int userId) {
             final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
@@ -27616,7 +23593,7 @@
         public boolean isPackageEphemeral(int userId, String packageName) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.getPackageLPr(packageName);
-                return ps != null ? ps.getInstantApp(userId) : false;
+                return ps != null && ps.getInstantApp(userId);
             }
         }
 
@@ -28481,10 +24458,6 @@
                 processName, uid, seinfo, pid);
     }
 
-    public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
-        return mCompilerStats.getPackageStats(pkgName);
-    }
-
     public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
         return getOrCreateCompilerPackageStats(pkg.getPackageName());
     }
@@ -28493,10 +24466,6 @@
         return mCompilerStats.getOrCreatePackageStats(pkgName);
     }
 
-    public void deleteCompilerPackageStats(String pkgName) {
-        mCompilerStats.deletePackageStats(pkgName);
-    }
-
     @Override
     public boolean isAutoRevokeWhitelisted(String packageName) {
         int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow(
@@ -28821,7 +24790,7 @@
      *
      * TODO(zhanghai): This should be removed once we finish migration of permission storage.
      */
-    private void writeSettingsLPrTEMP() {
+    void writeSettingsLPrTEMP() {
         mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
         mSettings.writeLPr();
     }
@@ -28979,11 +24948,6 @@
         return bOptions;
     }
 
-    @NonNull
-    public DomainVerificationService.Connection getDomainVerificationConnection() {
-        return mDomainVerificationConnection;
-    }
-
     @Override
     public void setKeepUninstalledPackages(List<String> packageList) {
         mContext.enforceCallingPermission(
@@ -29086,19 +25050,4 @@
     }
 }
 
-interface PackageSender {
-    /**
-     * @param userIds User IDs where the action occurred on a full application
-     * @param instantUserIds User IDs where the action occurred on an instant application
-     */
-    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[]> broadcastAllowList, @Nullable Bundle bOptions);
-    void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
-            boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
-            int dataLoaderType);
-    void notifyPackageAdded(String packageName, int uid);
-    void notifyPackageChanged(String packageName, int uid);
-    void notifyPackageRemoved(String packageName, int uid);
-}
+
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
new file mode 100644
index 0000000..e3581db
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.annotation.NonNull;
+import android.app.ActivityManagerInternal;
+import android.app.BroadcastOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.PowerExemptionManager;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
+
+final class PackageRemovedInfo {
+    final PackageSender mPackageSender;
+    String mRemovedPackage;
+    String mInstallerPackageName;
+    int mUid = -1;
+    int mRemovedAppId = -1;
+    int[] mOrigUsers;
+    int[] mRemovedUsers = null;
+    int[] mBroadcastUsers = null;
+    int[] mInstantUserIds = null;
+    SparseArray<Integer> mInstallReasons;
+    SparseArray<Integer> mUninstallReasons;
+    boolean mIsRemovedPackageSystemUpdate = false;
+    boolean mIsUpdate;
+    boolean mDataRemoved;
+    boolean mRemovedForAllUsers;
+    boolean mIsStaticSharedLib;
+    // a two dimensional array mapping userId to the set of appIds that can receive notice
+    // of package changes
+    SparseArray<int[]> mBroadcastAllowList;
+    // Clean up resources deleted packages.
+    InstallArgs mArgs = null;
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+    PackageRemovedInfo(PackageSender packageSender) {
+        mPackageSender = packageSender;
+    }
+
+    void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
+        sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
+    }
+
+    void sendSystemPackageUpdatedBroadcasts() {
+        if (mIsRemovedPackageSystemUpdate) {
+            sendSystemPackageUpdatedBroadcastsInternal();
+        }
+    }
+
+    private void sendSystemPackageUpdatedBroadcastsInternal() {
+        Bundle extras = new Bundle(2);
+        extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
+        extras.putBoolean(Intent.EXTRA_REPLACING, true);
+        mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
+                0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
+        mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
+                extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
+        mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
+                mRemovedPackage, null, null, null, null /* broadcastAllowList */,
+                getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
+        if (mInstallerPackageName != null) {
+            mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+                    mRemovedPackage, extras, 0 /*flags*/,
+                    mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+                    null);
+            mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+                    mRemovedPackage, extras, 0 /*flags*/,
+                    mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+                    null);
+        }
+    }
+
+    private static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
+            @PowerExemptionManager.ReasonCode int reasonCode) {
+        long duration = 10_000;
+        final ActivityManagerInternal amInternal =
+                LocalServices.getService(ActivityManagerInternal.class);
+        if (amInternal != null) {
+            duration = amInternal.getBootTimeTempAllowListDuration();
+        }
+        final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
+        bOptions.setTemporaryAppAllowlist(duration,
+                TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                reasonCode, "");
+        return bOptions;
+    }
+
+    private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
+        // Don't send static shared library removal broadcasts as these
+        // libs are visible only the apps that depend on them an one
+        // cannot remove the library if it has a dependency.
+        if (mIsStaticSharedLib) {
+            return;
+        }
+        Bundle extras = new Bundle(2);
+        final int removedUid = mRemovedAppId >= 0  ? mRemovedAppId : mUid;
+        extras.putInt(Intent.EXTRA_UID, removedUid);
+        extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
+        extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
+        extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
+        if (mIsUpdate || mIsRemovedPackageSystemUpdate) {
+            extras.putBoolean(Intent.EXTRA_REPLACING, true);
+        }
+        extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
+        if (mRemovedPackage != null) {
+            mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
+                    mRemovedPackage, extras, 0, null /*targetPackage*/, null,
+                    mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+            if (mInstallerPackageName != null) {
+                mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
+                        mRemovedPackage, extras, 0 /*flags*/,
+                        mInstallerPackageName, null, mBroadcastUsers, mInstantUserIds, null, null);
+            }
+            mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
+                    mRemovedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
+                    null /*finishedReceiver*/, mBroadcastUsers, mInstantUserIds,
+                    mBroadcastAllowList, null /*bOptions*/);
+            if (mDataRemoved && !mIsRemovedPackageSystemUpdate) {
+                mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
+                        mRemovedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
+                        null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+                mPackageSender.notifyPackageRemoved(mRemovedPackage, removedUid);
+            }
+        }
+        if (mRemovedAppId >= 0) {
+            // If a system app's updates are uninstalled the UID is not actually removed. Some
+            // services need to know the package name affected.
+            if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+                extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
+            }
+
+            mPackageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
+                    null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
+                    null, null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
+        }
+    }
+
+    void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
+        mRemovedUsers = userIds;
+        if (mRemovedUsers == null) {
+            mBroadcastUsers = null;
+            return;
+        }
+
+        mBroadcastUsers = EMPTY_INT_ARRAY;
+        mInstantUserIds = EMPTY_INT_ARRAY;
+        for (int i = userIds.length - 1; i >= 0; --i) {
+            final int userId = userIds[i];
+            if (deletedPackageSetting.getInstantApp(userId)) {
+                mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
+            } else {
+                mBroadcastUsers = ArrayUtils.appendInt(mBroadcastUsers, userId);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java
new file mode 100644
index 0000000..d380098
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageSender.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.IIntentReceiver;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+interface PackageSender {
+    /**
+     * @param userIds User IDs where the action occurred on a full application
+     * @param instantUserIds User IDs where the action occurred on an instant application
+     */
+    void sendPackageBroadcast(String action, String pkg,
+            Bundle extras, int flags, String targetPkg,
+            IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
+            @Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
+    void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
+            boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
+            int dataLoaderType);
+    void notifyPackageAdded(String packageName, int uid);
+    void notifyPackageChanged(String packageName, int uid);
+    void notifyPackageRemoved(String packageName, int uid);
+}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 3d1a841..717f3d5 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -176,6 +176,10 @@
         name = orig.name;
         realName = orig.realName;
         doCopy(orig);
+        // Clone the user states.
+        for (int i = 0; i < mUserState.size(); i++) {
+            mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i)));
+        }
     }
 
     public void setInstallerPackageName(String packageName) {
@@ -314,6 +318,7 @@
 
     void setInstalled(boolean inst, int userId) {
         modifyUserState(userId).installed = inst;
+        onChanged();
     }
 
     boolean getInstalled(int userId) {
@@ -326,6 +331,7 @@
 
     void setInstallReason(int installReason, int userId) {
         modifyUserState(userId).installReason = installReason;
+        onChanged();
     }
 
     int getUninstallReason(int userId) {
@@ -334,10 +340,13 @@
 
     void setUninstallReason(@UninstallReason int uninstallReason, int userId) {
         modifyUserState(userId).uninstallReason = uninstallReason;
+        onChanged();
     }
 
     boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
-        return modifyUserState(userId).setOverlayPaths(overlayPaths);
+        boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths);
+        onChanged();
+        return returnValue;
     }
 
     OverlayPaths getOverlayPaths(int userId) {
@@ -346,7 +355,10 @@
 
     boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths,
             int userId) {
-        return modifyUserState(userId).setSharedLibraryOverlayPaths(libName, overlayPaths);
+        boolean returnValue =  modifyUserState(userId)
+                .setSharedLibraryOverlayPaths(libName, overlayPaths);
+        onChanged();
+        return returnValue;
     }
 
     Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) {
@@ -395,6 +407,7 @@
 
     void setCeDataInode(long ceDataInode, int userId) {
         modifyUserState(userId).ceDataInode = ceDataInode;
+        onChanged();
     }
 
     boolean getStopped(int userId) {
@@ -403,6 +416,7 @@
 
     void setStopped(boolean stop, int userId) {
         modifyUserState(userId).stopped = stop;
+        onChanged();
     }
 
     boolean getNotLaunched(int userId) {
@@ -411,6 +425,7 @@
 
     void setNotLaunched(boolean stop, int userId) {
         modifyUserState(userId).notLaunched = stop;
+        onChanged();
     }
 
     boolean getHidden(int userId) {
@@ -419,6 +434,7 @@
 
     void setHidden(boolean hidden, int userId) {
         modifyUserState(userId).hidden = hidden;
+        onChanged();
     }
 
     int getDistractionFlags(int userId) {
@@ -427,6 +443,7 @@
 
     void setDistractionFlags(int distractionFlags, int userId) {
         modifyUserState(userId).distractionFlags = distractionFlags;
+        onChanged();
     }
 
     boolean getSuspended(int userId) {
@@ -487,6 +504,7 @@
 
     void setInstantApp(boolean instantApp, int userId) {
         modifyUserState(userId).instantApp = instantApp;
+        onChanged();
     }
 
     boolean getVirtulalPreload(int userId) {
@@ -495,6 +513,7 @@
 
     void setVirtualPreload(boolean virtualPreload, int userId) {
         modifyUserState(userId).virtualPreload = virtualPreload;
+        onChanged();
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
@@ -547,20 +566,24 @@
 
     void setEnabledComponents(ArraySet<String> components, int userId) {
         modifyUserState(userId).enabledComponents = components;
+        onChanged();
     }
 
     void setDisabledComponents(ArraySet<String> components, int userId) {
         modifyUserState(userId).disabledComponents = components;
+        onChanged();
     }
 
     void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
         modifyUserState(userId).enabledComponents = components != null
                 ? new ArraySet<String>(components) : null;
+        onChanged();
     }
 
     void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
         modifyUserState(userId).disabledComponents = components != null
                 ? new ArraySet<String>(components) : null;
+        onChanged();
     }
 
     PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
@@ -582,10 +605,12 @@
 
     void addDisabledComponent(String componentClassName, int userId) {
         modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
+        onChanged();
     }
 
     void addEnabledComponent(String componentClassName, int userId) {
         modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
+        onChanged();
     }
 
     boolean enableComponentLPw(String componentClassName, int userId) {
@@ -593,6 +618,9 @@
         boolean changed = state.disabledComponents != null
                 ? state.disabledComponents.remove(componentClassName) : false;
         changed |= state.enabledComponents.add(componentClassName);
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -601,6 +629,9 @@
         boolean changed = state.enabledComponents != null
                 ? state.enabledComponents.remove(componentClassName) : false;
         changed |= state.disabledComponents.add(componentClassName);
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -610,6 +641,9 @@
                 ? state.disabledComponents.remove(componentClassName) : false;
         changed |= state.enabledComponents != null
                 ? state.enabledComponents.remove(componentClassName) : false;
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -701,6 +735,7 @@
     PackageSettingBase setPath(@NonNull File path) {
         this.mPath = path;
         this.mPathString = path.toString();
+        onChanged();
         return this;
     }
 
@@ -722,7 +757,9 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component,
             @Nullable String label, @Nullable Integer icon, @UserIdInt int userId) {
-        return modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+        boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+        onChanged();
+        return returnValue;
     }
 
     /**
@@ -732,6 +769,7 @@
      */
     public void resetOverrideComponentLabelIcon(@UserIdInt int userId) {
         modifyUserState(userId).resetOverrideComponentLabelIcon();
+        onChanged();
     }
 
     /**
@@ -741,6 +779,7 @@
      */
     public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
         modifyUserState(userId).splashScreenTheme = themeName;
+        onChanged();
     }
 
     /**
@@ -776,6 +815,7 @@
      */
     public void setStatesOnCommit() {
         incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString()));
+        onChanged();
     }
 
     /**
@@ -783,6 +823,7 @@
      */
     public void setIncrementalStatesCallback(IncrementalStates.Callback callback) {
         incrementalStates.setCallback(callback);
+        onChanged();
     }
 
     /**
@@ -791,6 +832,7 @@
      */
     public void setLoadingProgress(float progress) {
         incrementalStates.setProgress(progress);
+        onChanged();
     }
 
     public long getFirstInstallTime() {
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index cb9c2e9..a652d1c 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -19,8 +19,6 @@
 import android.content.pm.PackageManager;
 import android.util.SparseBooleanArray;
 
-import com.android.server.pm.PackageManagerService.VerificationParams;
-
 /**
  * Tracks the package verification state for a particular package. Each package verification has a
  * required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list
diff --git a/services/core/java/com/android/server/pm/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java
new file mode 100644
index 0000000..a54ffa3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PrepareFailure.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.util.ExceptionUtils;
+
+final class PrepareFailure extends PackageManagerException {
+
+    public String mConflictingPackage;
+    public String mConflictingPermission;
+
+    PrepareFailure(int error) {
+        super(error, "Failed to prepare for install.");
+    }
+
+    PrepareFailure(int error, String detailMessage) {
+        super(error, detailMessage);
+    }
+
+    PrepareFailure(String message, Exception e) {
+        super(((PackageManagerException) e).error,
+                ExceptionUtils.getCompleteMessage(message, e));
+    }
+
+    PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
+            String conflictingPackage) {
+        mConflictingPermission = conflictingPermission;
+        mConflictingPackage = conflictingPackage;
+        return this;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java
new file mode 100644
index 0000000..4e08e16
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PrepareResult.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/**
+ * The set of data needed to successfully install the prepared package. This includes data that
+ * will be used to scan and reconcile the package.
+ */
+final class PrepareResult {
+    public final boolean mReplace;
+    public final int mScanFlags;
+    public final int mParseFlags;
+    @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
+    public final AndroidPackage mExistingPackage;
+    public final ParsedPackage mPackageToScan;
+    public final boolean mClearCodeCache;
+    public final boolean mSystem;
+    public final PackageSetting mOriginalPs;
+    public final PackageSetting mDisabledPs;
+
+    PrepareResult(boolean replace, int scanFlags,
+            int parseFlags, AndroidPackage existingPackage,
+            ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
+            PackageSetting originalPs, PackageSetting disabledPs) {
+        mReplace = replace;
+        mScanFlags = scanFlags;
+        mParseFlags = parseFlags;
+        mExistingPackage = existingPackage;
+        mPackageToScan = packageToScan;
+        mClearCodeCache = clearCodeCache;
+        mSystem = system;
+        mOriginalPs = originalPs;
+        mDisabledPs = disabledPs;
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/services/core/java/com/android/server/pm/ReconcileFailure.java
similarity index 60%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to services/core/java/com/android/server/pm/ReconcileFailure.java
index c7c2ad8..c9615ff 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/services/core/java/com/android/server/pm/ReconcileFailure.java
@@ -14,6 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.pm;
 
-parcelable InputConnectionCommand;
+final class ReconcileFailure extends PackageManagerException {
+    ReconcileFailure(String message) {
+        super("Reconcile failed: " + message);
+    }
+    ReconcileFailure(int reason, String message) {
+        super(reason, "Reconcile failed: " + message);
+    }
+    ReconcileFailure(PackageManagerException e) {
+        this(e.error, e.getMessage());
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java
new file mode 100644
index 0000000..3188138
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ReconcileRequest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.SharedLibraryInfo;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.utils.WatchedLongSparseArray;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Package scan results and related request details used to reconcile the potential addition of
+ * one or more packages to the system.
+ *
+ * Reconcile will take a set of package details that need to be committed to the system and make
+ * sure that they are valid in the context of the system and the other installing apps. Any
+ * invalid state or app will result in a failed reconciliation and thus whatever operation (such
+ * as install) led to the request.
+ */
+final class ReconcileRequest {
+    public final Map<String, ScanResult> mScannedPackages;
+
+    public final Map<String, AndroidPackage> mAllPackages;
+    public final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> mSharedLibrarySource;
+    public final Map<String, InstallArgs> mInstallArgs;
+    public final Map<String, PackageInstalledInfo> mInstallResults;
+    public final Map<String, PrepareResult> mPreparedPackages;
+    public final Map<String, Settings.VersionInfo> mVersionInfos;
+    public final Map<String, PackageSetting> mLastStaticSharedLibSettings;
+
+    ReconcileRequest(Map<String, ScanResult> scannedPackages,
+            Map<String, InstallArgs> installArgs,
+            Map<String, PackageInstalledInfo> installResults,
+            Map<String, PrepareResult> preparedPackages,
+            Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+            Map<String, AndroidPackage> allPackages,
+            Map<String, Settings.VersionInfo> versionInfos,
+            Map<String, PackageSetting> lastStaticSharedLibSettings) {
+        mScannedPackages = scannedPackages;
+        mInstallArgs = installArgs;
+        mInstallResults = installResults;
+        mPreparedPackages = preparedPackages;
+        mSharedLibrarySource = sharedLibrarySource;
+        mAllPackages = allPackages;
+        mVersionInfos = versionInfos;
+        mLastStaticSharedLibSettings = lastStaticSharedLibSettings;
+    }
+
+    ReconcileRequest(Map<String, ScanResult> scannedPackages,
+            Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
+            Map<String, AndroidPackage> allPackages,
+            Map<String, Settings.VersionInfo> versionInfos,
+            Map<String, PackageSetting> lastStaticSharedLibSettings) {
+        this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
+                Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
+                lastStaticSharedLibSettings);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java
new file mode 100644
index 0000000..f78249f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ReconciledPackage.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SigningDetails;
+import android.util.ArrayMap;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A container of all data needed to commit a package to in-memory data structures and to disk.
+ * TODO: move most of the data contained here into a PackageSetting for commit.
+ */
+final class ReconciledPackage {
+    public final ReconcileRequest mRequest;
+    public final PackageSetting mPkgSetting;
+    public final ScanResult mScanResult;
+    // TODO: Remove install-specific details from the reconcile result
+    public final PackageInstalledInfo mInstallResult;
+    @Nullable public final PrepareResult mPrepareResult;
+    @Nullable public final InstallArgs mInstallArgs;
+    public final DeletePackageAction mDeletePackageAction;
+    public final List<SharedLibraryInfo> mAllowedSharedLibraryInfos;
+    public final SigningDetails mSigningDetails;
+    public final boolean mSharedUserSignaturesChanged;
+    public ArrayList<SharedLibraryInfo> mCollectedSharedLibraryInfos;
+    public final boolean mRemoveAppKeySetData;
+
+    ReconciledPackage(ReconcileRequest request,
+            InstallArgs installArgs,
+            PackageSetting pkgSetting,
+            PackageInstalledInfo installResult,
+            PrepareResult prepareResult,
+            ScanResult scanResult,
+            DeletePackageAction deletePackageAction,
+            List<SharedLibraryInfo> allowedSharedLibraryInfos,
+            SigningDetails signingDetails,
+            boolean sharedUserSignaturesChanged,
+            boolean removeAppKeySetData) {
+        mRequest = request;
+        mInstallArgs = installArgs;
+        mPkgSetting = pkgSetting;
+        mInstallResult = installResult;
+        mPrepareResult = prepareResult;
+        mScanResult = scanResult;
+        mDeletePackageAction = deletePackageAction;
+        mAllowedSharedLibraryInfos = allowedSharedLibraryInfos;
+        mSigningDetails = signingDetails;
+        mSharedUserSignaturesChanged = sharedUserSignaturesChanged;
+        mRemoveAppKeySetData = removeAppKeySetData;
+    }
+
+    /**
+     * Returns a combined set of packages containing the packages already installed combined
+     * with the package(s) currently being installed. The to-be installed packages take
+     * precedence and may shadow already installed packages.
+     */
+    Map<String, AndroidPackage> getCombinedAvailablePackages() {
+        final ArrayMap<String, AndroidPackage> combined =
+                new ArrayMap<>(mRequest.mAllPackages.size() + mRequest.mScannedPackages.size());
+
+        combined.putAll(mRequest.mAllPackages);
+
+        for (ScanResult scanResult : mRequest.mScannedPackages.values()) {
+            combined.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage);
+        }
+
+        return combined;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index e28540c..a7e1a62 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -571,7 +571,7 @@
      * In all cases, a return value of null should be interpreted as the apk failing
      * to match this Policy instance; i.e. failing this policy stanza.
      * </p>
-     * @param pkg the apk to check given as a PackageParser.Package object
+     * @param pkg the apk to check given as a AndroidPackage object
      * @return A string representing the seinfo matched during policy lookup.
      *         A value of null can also be returned if no match occured.
      */
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
new file mode 100644
index 0000000..482b79c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/** A package to be scanned */
+@VisibleForTesting
+final class ScanRequest {
+    /** The parsed package */
+    @NonNull public final ParsedPackage mParsedPackage;
+    /** The package this package replaces */
+    @Nullable public final AndroidPackage mOldPkg;
+    /** Shared user settings, if the package has a shared user */
+    @Nullable public final SharedUserSetting mSharedUserSetting;
+    /**
+     * Package settings of the currently installed version.
+     * <p><em>IMPORTANT:</em> The contents of this object may be modified
+     * during scan.
+     */
+    @Nullable public final PackageSetting mPkgSetting;
+    /** A copy of the settings for the currently installed version */
+    @Nullable public final PackageSetting mOldPkgSetting;
+    /** Package settings for the disabled version on the /system partition */
+    @Nullable public final PackageSetting mDisabledPkgSetting;
+    /** Package settings for the installed version under its original package name */
+    @Nullable public final PackageSetting mOriginalPkgSetting;
+    /** The real package name of a renamed application */
+    @Nullable public final String mRealPkgName;
+    public final @ParsingPackageUtils.ParseFlags int mParseFlags;
+    public final @PackageManagerService.ScanFlags int mScanFlags;
+    /** The user for which the package is being scanned */
+    @Nullable public final UserHandle mUser;
+    /** Whether or not the platform package is being scanned */
+    public final boolean mIsPlatformPackage;
+    /** Override value for package ABI if set during install */
+    @Nullable public final String mCpuAbiOverride;
+
+    ScanRequest(
+            @NonNull ParsedPackage parsedPackage,
+            @Nullable SharedUserSetting sharedUserSetting,
+            @Nullable AndroidPackage oldPkg,
+            @Nullable PackageSetting pkgSetting,
+            @Nullable PackageSetting disabledPkgSetting,
+            @Nullable PackageSetting originalPkgSetting,
+            @Nullable String realPkgName,
+            @ParsingPackageUtils.ParseFlags int parseFlags,
+            @PackageManagerService.ScanFlags int scanFlags,
+            boolean isPlatformPackage,
+            @Nullable UserHandle user,
+            @Nullable String cpuAbiOverride) {
+        mParsedPackage = parsedPackage;
+        mOldPkg = oldPkg;
+        mPkgSetting = pkgSetting;
+        mSharedUserSetting = sharedUserSetting;
+        mOldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
+        mDisabledPkgSetting = disabledPkgSetting;
+        mOriginalPkgSetting = originalPkgSetting;
+        mRealPkgName = realPkgName;
+        mParseFlags = parseFlags;
+        mScanFlags = scanFlags;
+        mIsPlatformPackage = isPlatformPackage;
+        mUser = user;
+        mCpuAbiOverride = cpuAbiOverride;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java
new file mode 100644
index 0000000..34f86ba
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ScanResult.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/** The result of a package scan. */
+@VisibleForTesting
+final class ScanResult {
+    /** The request that initiated the scan that produced this result. */
+    public final ScanRequest mRequest;
+    /** Whether or not the package scan was successful */
+    public final boolean mSuccess;
+    /**
+     * Whether or not the original PackageSetting needs to be updated with this result on
+     * commit.
+     */
+    public final boolean mExistingSettingCopied;
+    /**
+     * Whether or not the original PackageSetting needs to be updated with
+     * a new uid. Useful when leaving a sharedUserID.
+     */
+    public final boolean mNeedsNewAppId;
+    /**
+     * The final package settings. This may be the same object passed in
+     * the {@link ScanRequest}, but, with modified values.
+     */
+    @Nullable
+    public final PackageSetting mPkgSetting;
+    /** ABI code paths that have changed in the package scan */
+    @Nullable public final List<String> mChangedAbiCodePath;
+
+    public final SharedLibraryInfo mStaticSharedLibraryInfo;
+
+    public final List<SharedLibraryInfo> mDynamicSharedLibraryInfos;
+
+    ScanResult(
+            ScanRequest request, boolean success,
+            @Nullable PackageSetting pkgSetting,
+            @Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
+            boolean needsNewAppId,
+            SharedLibraryInfo staticSharedLibraryInfo,
+            List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
+        mRequest = request;
+        mSuccess = success;
+        mPkgSetting = pkgSetting;
+        mChangedAbiCodePath = changedAbiCodePath;
+        mExistingSettingCopied = existingSettingCopied;
+        mNeedsNewAppId = needsNewAppId;
+        mStaticSharedLibraryInfo = staticSharedLibraryInfo;
+        mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3995cc6..902263a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1126,9 +1126,9 @@
      *         already registered.
      * @throws PackageManagerException If a user ID could not be allocated.
      */
-    boolean registerAppIdLPw(PackageSetting p) throws PackageManagerException {
+    boolean registerAppIdLPw(PackageSetting p, boolean forceNew) throws PackageManagerException {
         final boolean createdNew;
-        if (p.appId == 0) {
+        if (p.appId == 0 || forceNew) {
             // Assign new user ID
             p.appId = acquireAndRegisterNewAppIdLPw(p);
             createdNew = true;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 8ddbe08..8bfa728 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -88,7 +88,7 @@
         uidFlags = orig.uidFlags;
         uidPrivateFlags = orig.uidPrivateFlags;
         packages = new ArraySet(orig.packages);
-        // A PackageParser.SigningDetails seems to consist solely of final attributes, so
+        // A SigningDetails seems to consist solely of final attributes, so
         // it is safe to copy the reference.
         signatures.mSigningDetails = orig.signatures.mSigningDetails;
         signaturesChanged = orig.signaturesChanged;
diff --git a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl b/services/core/java/com/android/server/pm/SystemDeleteException.java
similarity index 72%
copy from core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
copy to services/core/java/com/android/server/pm/SystemDeleteException.java
index c7c2ad8..410876f 100644
--- a/core/java/com/android/internal/inputmethod/InputConnectionCommand.aidl
+++ b/services/core/java/com/android/server/pm/SystemDeleteException.java
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.internal.inputmethod;
+package com.android.server.pm;
 
-parcelable InputConnectionCommand;
+final class SystemDeleteException extends Exception {
+    final PackageManagerException mReason;
+
+    SystemDeleteException(PackageManagerException reason) {
+        mReason = reason;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0d909a9..e8182e0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5087,8 +5087,11 @@
                             Binder.restoreCallingIdentity(ident);
                         }
                     }
-                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s%s%s%s\n", i, user.id,
+                    pw.printf("%d: id=%d, name=%s, type=%s, flags=%s%s%s%s%s%s%s%s%s\n",
+                            i,
+                            user.id,
                             user.name,
+                            user.userType.replace("android.os.usertype.", ""),
                             UserInfo.flagsToString(user.flags),
                             hasParent ? " (parentId=" + user.profileGroupId + ")" : "",
                             running ? " (running)" : "",
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 6e6d7c3..849d1a338 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -487,7 +487,7 @@
     /**
      * Gets the system package names that should be installed on users of the given user type, as
      * determined by SystemConfig, the allowlist mode, and the apps actually on the device.
-     * Names are the {@link PackageParser.Package#packageName}, not necessarily the manifest names.
+     * Names are the {@link AndroidPackage#getPackageName()}, not necessarily the manifest names.
      *
      * Returns null if all system packages should be installed (due to enforce-mode being off).
      */
diff --git a/services/core/java/com/android/server/pm/VerificationInfo.java b/services/core/java/com/android/server/pm/VerificationInfo.java
new file mode 100644
index 0000000..3d4a42c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/VerificationInfo.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.net.Uri;
+
+final class VerificationInfo {
+    /** URI referencing where the package was downloaded from. */
+    final Uri mOriginatingUri;
+
+    /** HTTP referrer URI associated with the originatingURI. */
+    final Uri mReferrer;
+
+    /** UID of the application that the install request originated from. */
+    final int mOriginatingUid;
+
+    /** UID of application requesting the install */
+    final int mInstallerUid;
+
+    VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
+        mOriginatingUri = originatingUri;
+        mReferrer = referrer;
+        mOriginatingUid = originatingUid;
+        mInstallerUid = installerUid;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
new file mode 100644
index 0000000..3c499de
--- /dev/null
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_VERSION_CODE;
+import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
+import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
+import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
+import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.DataLoaderType;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.VerifierInfo;
+import android.content.pm.parsing.PackageLite;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.server.DeviceIdleInternal;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import java.io.File;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+final class VerificationParams extends HandlerParams {
+    /**
+     * Whether integrity verification is enabled by default.
+     */
+    private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
+    /**
+     * The default maximum time to wait for the integrity verification to return in
+     * milliseconds.
+     */
+    private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
+    /**
+     * Whether verification is enabled by default.
+     */
+    private static final boolean DEFAULT_VERIFY_ENABLE = true;
+    /**
+     * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+     * rollback within that period, the install will proceed without rollback enabled.
+     *
+     * <p>If flag value is negative, the default value will be assigned.
+     *
+     * Flag type: {@code long}
+     * Namespace: NAMESPACE_ROLLBACK
+     */
+    private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+    /**
+     * The default duration to wait for rollback to be enabled in
+     * milliseconds.
+     */
+    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
+
+    final OriginInfo mOriginInfo;
+    final IPackageInstallObserver2 mObserver;
+    final int mInstallFlags;
+    @NonNull
+    final InstallSource mInstallSource;
+    final String mPackageAbiOverride;
+    final VerificationInfo mVerificationInfo;
+    final SigningDetails mSigningDetails;
+    @Nullable
+    MultiPackageVerificationParams mParentVerificationParams;
+    final long mRequiredInstalledVersionCode;
+    final int mDataLoaderType;
+    final int mSessionId;
+
+    private boolean mWaitForVerificationToComplete;
+    private boolean mWaitForIntegrityVerificationToComplete;
+    private boolean mWaitForEnableRollbackToComplete;
+    private int mRet = PackageManager.INSTALL_SUCCEEDED;
+    private String mErrorMessage = null;
+
+    final PackageLite mPackageLite;
+    final PackageManagerService mPm;
+
+    VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
+            PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+            int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
+            PackageManagerService pm) {
+        super(user);
+        mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
+        mObserver = observer;
+        mInstallFlags = sessionParams.installFlags;
+        mInstallSource = installSource;
+        mPackageAbiOverride = sessionParams.abiOverride;
+        mVerificationInfo = new VerificationInfo(
+                sessionParams.originatingUri,
+                sessionParams.referrerUri,
+                sessionParams.originatingUid,
+                installerUid
+        );
+        mSigningDetails = signingDetails;
+        mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+        mDataLoaderType = (sessionParams.dataLoaderParams != null)
+                ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+        mSessionId = sessionId;
+        mPackageLite = lite;
+        mPm = pm;
+    }
+
+    @Override
+    public String toString() {
+        return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+                + " file=" + mOriginInfo.mFile + "}";
+    }
+
+    public void handleStartCopy() {
+        PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
+                mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
+
+        Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
+                pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
+        setReturnCode(ret.first, ret.second);
+        if (mRet != INSTALL_SUCCEEDED) {
+            return;
+        }
+
+        // Perform package verification and enable rollback (unless we are simply moving the
+        // package).
+        if (!mOriginInfo.mExisting) {
+            if ((mInstallFlags & PackageManager.INSTALL_APEX) == 0) {
+                // TODO(b/182426975): treat APEX as APK when APK verification is concerned
+                sendApkVerificationRequest(pkgLite);
+            }
+            if ((mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+                sendEnableRollbackRequest();
+            }
+        }
+    }
+
+    void sendApkVerificationRequest(PackageInfoLite pkgLite) {
+        final int verificationId = mPm.mPendingVerificationToken++;
+
+        PackageVerificationState verificationState =
+                new PackageVerificationState(this);
+        mPm.mPendingVerification.append(verificationId, verificationState);
+
+        sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
+        sendPackageVerificationRequest(
+                verificationId, pkgLite, verificationState);
+
+        // If both verifications are skipped, we should remove the state.
+        if (verificationState.areAllVerificationsComplete()) {
+            mPm.mPendingVerification.remove(verificationId);
+        }
+    }
+
+    void sendEnableRollbackRequest() {
+        final int enableRollbackToken = mPm.mPendingEnableRollbackToken++;
+        Trace.asyncTraceBegin(
+                TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+        mPm.mPendingEnableRollback.append(enableRollbackToken, this);
+
+        Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+        enableRollbackIntent.putExtra(
+                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
+                enableRollbackToken);
+        enableRollbackIntent.putExtra(
+                PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
+                mSessionId);
+        enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
+        enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        // Allow the broadcast to be sent before boot complete.
+        // This is needed when committing the apk part of a staged
+        // session in early boot. The rollback manager registers
+        // its receiver early enough during the boot process that
+        // it will not miss the broadcast.
+        enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+        mPm.mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
+                android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
+
+        mWaitForEnableRollbackToComplete = true;
+
+        // the duration to wait for rollback to be enabled, in millis
+        long rollbackTimeout = DeviceConfig.getLong(
+                DeviceConfig.NAMESPACE_ROLLBACK,
+                PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+                DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
+        if (rollbackTimeout < 0) {
+            rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
+        }
+        final Message msg = mPm.mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
+        msg.arg1 = enableRollbackToken;
+        msg.arg2 = mSessionId;
+        mPm.mHandler.sendMessageDelayed(msg, rollbackTimeout);
+    }
+
+    /**
+     * Send a request to check the integrity of the package.
+     */
+    void sendIntegrityVerificationRequest(
+            int verificationId,
+            PackageInfoLite pkgLite,
+            PackageVerificationState verificationState) {
+        if (!isIntegrityVerificationEnabled()) {
+            // Consider the integrity check as passed.
+            verificationState.setIntegrityVerificationResult(
+                    PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+            return;
+        }
+
+        final Intent integrityVerification =
+                new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
+
+        integrityVerification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
+                PACKAGE_MIME_TYPE);
+
+        final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                | Intent.FLAG_RECEIVER_FOREGROUND;
+        integrityVerification.addFlags(flags);
+
+        integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
+        integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
+        integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
+        integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
+        populateInstallerExtras(integrityVerification);
+
+        // send to integrity component only.
+        integrityVerification.setPackage("android");
+
+        final BroadcastOptions options = BroadcastOptions.makeBasic();
+
+        mPm.mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
+                /* receiverPermission= */ null,
+                /* appOp= */ AppOpsManager.OP_NONE,
+                /* options= */ options.toBundle(),
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        final Message msg =
+                                mPm.mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
+                        msg.arg1 = verificationId;
+                        mPm.mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
+                    }
+                }, /* scheduler= */ null,
+                /* initialCode= */ 0,
+                /* initialData= */ null,
+                /* initialExtras= */ null);
+
+        Trace.asyncTraceBegin(
+                TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
+
+        // stop the copy until verification succeeds.
+        mWaitForIntegrityVerificationToComplete = true;
+    }
+
+
+    /**
+     * Get the integrity verification timeout.
+     *
+     * @return verification timeout in milliseconds
+     */
+    private long getIntegrityVerificationTimeout() {
+        long timeout = Settings.Global.getLong(mPm.mContext.getContentResolver(),
+                Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
+                DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+        // The setting can be used to increase the timeout but not decrease it, since that is
+        // equivalent to disabling the integrity component.
+        return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
+    }
+
+    /**
+     * Check whether or not integrity verification has been enabled.
+     */
+    private boolean isIntegrityVerificationEnabled() {
+        // We are not exposing this as a user-configurable setting because we don't want to provide
+        // an easy way to get around the integrity check.
+        return DEFAULT_INTEGRITY_VERIFY_ENABLE;
+    }
+
+    /**
+     * Send a request to verifier(s) to verify the package if necessary.
+     */
+    void sendPackageVerificationRequest(
+            int verificationId,
+            PackageInfoLite pkgLite,
+            PackageVerificationState verificationState) {
+
+        // TODO: http://b/22976637
+        // Apps installed for "all" users use the device owner to verify the app
+        UserHandle verifierUser = getUser();
+        if (verifierUser == UserHandle.ALL) {
+            verifierUser = UserHandle.SYSTEM;
+        }
+
+        /*
+         * Determine if we have any installed package verifiers. If we
+         * do, then we'll defer to them to verify the packages.
+         */
+        final int requiredUid = mPm.mRequiredVerifierPackage == null ? -1
+                : mPm.getPackageUid(mPm.mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+                        verifierUser.getIdentifier());
+        verificationState.setRequiredVerifierUid(requiredUid);
+        final int installerUid =
+                mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid;
+        final boolean isVerificationEnabled = isVerificationEnabled(
+                pkgLite, verifierUser.getIdentifier(), mInstallFlags, installerUid);
+        final boolean isV4Signed =
+                (mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
+        final boolean isIncrementalInstall =
+                (mDataLoaderType == DataLoaderType.INCREMENTAL);
+        // NOTE: We purposefully skip verification for only incremental installs when there's
+        // a v4 signature block. Otherwise, proceed with verification as usual.
+        if (!mOriginInfo.mExisting
+                && isVerificationEnabled
+                && (!isIncrementalInstall || !isV4Signed)) {
+            final Intent verification = new Intent(
+                    Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+            verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
+                    PACKAGE_MIME_TYPE);
+            verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+            // Query all live verifiers based on current user state
+            final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification,
+                    PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
+
+            if (DEBUG_VERIFY) {
+                Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent "
+                        + verification.toString() + " with " + pkgLite.verifiers.length
+                        + " optional verifiers");
+            }
+
+            verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
+
+            verification.putExtra(
+                    PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags);
+
+            verification.putExtra(
+                    PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
+
+            verification.putExtra(
+                    PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
+
+            verification.putExtra(
+                    PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+                    pkgLite.getLongVersionCode());
+
+            populateInstallerExtras(verification);
+
+            final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
+                    receivers.getList(), verificationState);
+
+            DeviceIdleInternal idleController =
+                    mPm.mInjector.getLocalService(DeviceIdleInternal.class);
+            final long idleDuration = mPm.getVerificationTimeout();
+            final BroadcastOptions options = BroadcastOptions.makeBasic();
+            options.setTemporaryAppAllowlist(idleDuration,
+                    TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    REASON_PACKAGE_VERIFIER, "");
+
+            /*
+             * If any sufficient verifiers were listed in the package
+             * manifest, attempt to ask them.
+             */
+            if (sufficientVerifiers != null) {
+                final int n = sufficientVerifiers.size();
+                if (n == 0) {
+                    String errorMsg = "Additional verifiers required, but none installed.";
+                    Slog.i(TAG, errorMsg);
+                    setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
+                } else {
+                    for (int i = 0; i < n; i++) {
+                        final ComponentName verifierComponent = sufficientVerifiers.get(i);
+                        idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+                                verifierComponent.getPackageName(), idleDuration,
+                                verifierUser.getIdentifier(), false,
+                                REASON_PACKAGE_VERIFIER, "package verifier");
+
+                        final Intent sufficientIntent = new Intent(verification);
+                        sufficientIntent.setComponent(verifierComponent);
+                        mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
+                                /* receiverPermission= */ null,
+                                options.toBundle());
+                    }
+                }
+            }
+
+            if (mPm.mRequiredVerifierPackage != null) {
+                final ComponentName requiredVerifierComponent = matchComponentForVerifier(
+                        mPm.mRequiredVerifierPackage, receivers.getList());
+                /*
+                 * Send the intent to the required verification agent,
+                 * but only start the verification timeout after the
+                 * target BroadcastReceivers have run.
+                 */
+                verification.setComponent(requiredVerifierComponent);
+                idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+                        mPm.mRequiredVerifierPackage, idleDuration,
+                        verifierUser.getIdentifier(), false,
+                        REASON_PACKAGE_VERIFIER, "package verifier");
+                mPm.mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
+                        android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+                        /* appOp= */ AppOpsManager.OP_NONE,
+                        /* options= */ options.toBundle(),
+                        new BroadcastReceiver() {
+                            @Override
+                            public void onReceive(Context context, Intent intent) {
+                                final Message msg = mPm.mHandler
+                                        .obtainMessage(CHECK_PENDING_VERIFICATION);
+                                msg.arg1 = verificationId;
+                                mPm.mHandler.sendMessageDelayed(msg, mPm.getVerificationTimeout());
+                            }
+                        }, null, 0, null, null);
+
+                Trace.asyncTraceBegin(
+                        TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
+                /*
+                 * We don't want the copy to proceed until verification
+                 * succeeds.
+                 */
+                mWaitForVerificationToComplete = true;
+            }
+        } else {
+            verificationState.setVerifierResponse(
+                    requiredUid, PackageManager.VERIFICATION_ALLOW);
+        }
+    }
+
+
+    private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
+            List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
+        if (pkgInfo.verifiers.length == 0) {
+            return null;
+        }
+
+        final int n = pkgInfo.verifiers.length;
+        final List<ComponentName> sufficientVerifiers = new ArrayList<>(n + 1);
+        for (int i = 0; i < n; i++) {
+            final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
+
+            final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
+                    receivers);
+            if (comp == null) {
+                continue;
+            }
+
+            final int verifierUid = getUidForVerifier(verifierInfo);
+            if (verifierUid == -1) {
+                continue;
+            }
+
+            if (DEBUG_VERIFY) {
+                Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
+                        + " with the correct signature");
+            }
+            sufficientVerifiers.add(comp);
+            verificationState.addSufficientVerifier(verifierUid);
+        }
+
+        return sufficientVerifiers;
+    }
+
+    private int getUidForVerifier(VerifierInfo verifierInfo) {
+        synchronized (mPm.mLock) {
+            final AndroidPackage pkg = mPm.mPackages.get(verifierInfo.packageName);
+            if (pkg == null) {
+                return -1;
+            } else if (pkg.getSigningDetails().getSignatures().length != 1) {
+                Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+                        + " has more than one signature; ignoring");
+                return -1;
+            }
+
+            /*
+             * If the public key of the package's signature does not match
+             * our expected public key, then this is a different package and
+             * we should skip.
+             */
+
+            final byte[] expectedPublicKey;
+            try {
+                final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
+                final PublicKey publicKey = verifierSig.getPublicKey();
+                expectedPublicKey = publicKey.getEncoded();
+            } catch (CertificateException e) {
+                return -1;
+            }
+
+            final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
+
+            if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
+                Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+                        + " does not have the expected public key; ignoring");
+                return -1;
+            }
+
+            return pkg.getUid();
+        }
+    }
+
+    private static ComponentName matchComponentForVerifier(String packageName,
+            List<ResolveInfo> receivers) {
+        ActivityInfo targetReceiver = null;
+
+        final int nr = receivers.size();
+        for (int i = 0; i < nr; i++) {
+            final ResolveInfo info = receivers.get(i);
+            if (info.activityInfo == null) {
+                continue;
+            }
+
+            if (packageName.equals(info.activityInfo.packageName)) {
+                targetReceiver = info.activityInfo;
+                break;
+            }
+        }
+
+        if (targetReceiver == null) {
+            return null;
+        }
+
+        return new ComponentName(targetReceiver.packageName, targetReceiver.name);
+    }
+
+    /**
+     * Check whether or not package verification has been enabled.
+     *
+     * @return true if verification should be performed
+     */
+    private boolean isVerificationEnabled(
+            PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
+        if (!DEFAULT_VERIFY_ENABLE) {
+            return false;
+        }
+
+        // Check if installing from ADB
+        if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
+            if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
+                return true;
+            }
+            // Check if the developer wants to skip verification for ADB installs
+            if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
+                synchronized (mPm.mLock) {
+                    if (mPm.mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
+                        // Always verify fresh install
+                        return true;
+                    }
+                }
+                // Only skip when apk is debuggable
+                return !pkgInfoLite.debuggable;
+            }
+            return Settings.Global.getInt(mPm.mContext.getContentResolver(),
+                    Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
+        }
+
+        // only when not installed from ADB, skip verification for instant apps when
+        // the installer and verifier are the same.
+        if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+            if (mPm.mInstantAppInstallerActivity != null
+                    && mPm.mInstantAppInstallerActivity.packageName.equals(
+                    mPm.mRequiredVerifierPackage)) {
+                try {
+                    mPm.mInjector.getSystemService(AppOpsManager.class)
+                            .checkPackage(installerUid, mPm.mRequiredVerifierPackage);
+                    if (DEBUG_VERIFY) {
+                        Slog.i(TAG, "disable verification for instant app");
+                    }
+                    return false;
+                } catch (SecurityException ignore) { }
+            }
+        }
+        return true;
+    }
+
+    void populateInstallerExtras(Intent intent) {
+        intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
+                mInstallSource.initiatingPackageName);
+
+        if (mVerificationInfo != null) {
+            if (mVerificationInfo.mOriginatingUri != null) {
+                intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
+                        mVerificationInfo.mOriginatingUri);
+            }
+            if (mVerificationInfo.mReferrer != null) {
+                intent.putExtra(Intent.EXTRA_REFERRER,
+                        mVerificationInfo.mReferrer);
+            }
+            if (mVerificationInfo.mOriginatingUid >= 0) {
+                intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
+                        mVerificationInfo.mOriginatingUid);
+            }
+            if (mVerificationInfo.mInstallerUid >= 0) {
+                intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
+                        mVerificationInfo.mInstallerUid);
+            }
+        }
+    }
+
+    void setReturnCode(int ret, String message) {
+        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+            // Only update mRet if it was previously INSTALL_SUCCEEDED to
+            // ensure we do not overwrite any previous failure results.
+            mRet = ret;
+            mErrorMessage = message;
+        }
+    }
+
+    void handleVerificationFinished() {
+        mWaitForVerificationToComplete = false;
+        handleReturnCode();
+    }
+
+    void handleIntegrityVerificationFinished() {
+        mWaitForIntegrityVerificationToComplete = false;
+        handleReturnCode();
+    }
+
+
+    void handleRollbackEnabled() {
+        // TODO(b/112431924): Consider halting the install if we
+        // couldn't enable rollback.
+        mWaitForEnableRollbackToComplete = false;
+        handleReturnCode();
+    }
+
+    @Override
+    void handleReturnCode() {
+        if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
+                || mWaitForEnableRollbackToComplete) {
+            return;
+        }
+        sendVerificationCompleteNotification();
+    }
+
+    private void sendVerificationCompleteNotification() {
+        if (mParentVerificationParams != null) {
+            mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
+        } else {
+            try {
+                mObserver.onPackageInstalled(null, mRet, mErrorMessage,
+                        new Bundle());
+            } catch (RemoteException e) {
+                Slog.i(TAG, "Observer no longer exists.");
+            }
+        }
+    }
+
+    public void verifyStage() {
+        mPm.mHandler.post(this::startCopy);
+    }
+
+    public void verifyStage(List<VerificationParams> children)
+            throws PackageManagerException {
+        final MultiPackageVerificationParams params =
+                new MultiPackageVerificationParams(this, children);
+        mPm.mHandler.post(params::startCopy);
+    }
+
+    /**
+     * Container for a multi-package install which refers to all install sessions and args being
+     * committed together.
+     */
+    static final class MultiPackageVerificationParams extends HandlerParams {
+        private final IPackageInstallObserver2 mObserver;
+        private final List<VerificationParams> mChildParams;
+        private final Map<VerificationParams, Integer> mVerificationState;
+
+        MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children)
+                throws PackageManagerException {
+            super(parent.getUser());
+            if (children.size() == 0) {
+                throw new PackageManagerException("No child sessions found!");
+            }
+            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;
+            }
+            mVerificationState = new ArrayMap<>(mChildParams.size());
+            mObserver = parent.mObserver;
+        }
+
+        @Override
+        void handleStartCopy() {
+            for (VerificationParams params : mChildParams) {
+                params.handleStartCopy();
+            }
+        }
+
+        @Override
+        void handleReturnCode() {
+            for (VerificationParams params : mChildParams) {
+                params.handleReturnCode();
+            }
+        }
+
+        void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
+            mVerificationState.put(child, currentStatus);
+            if (mVerificationState.size() != mChildParams.size()) {
+                return;
+            }
+            int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+            String errorMsg = null;
+            for (VerificationParams params : mVerificationState.keySet()) {
+                int status = params.mRet;
+                if (status == PackageManager.INSTALL_UNKNOWN) {
+                    return;
+                } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+                    completeStatus = status;
+                    errorMsg = params.mErrorMessage;
+                    break;
+                }
+            }
+            try {
+                mObserver.onPackageInstalled(null, completeStatus,
+                        errorMsg, new Bundle());
+            } catch (RemoteException e) {
+                Slog.i(TAG, "Observer no longer exists.");
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 203356d..f467a7f 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -22,7 +22,6 @@
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.ParsingPackageUtils;
 import android.content.pm.parsing.ParsingUtils;
@@ -47,7 +46,7 @@
 import java.util.List;
 
 /**
- * The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
+ * The v2 of package parsing for use when parsing is initiated in the server and must
  * contain state contained by the server.
  *
  * The {@link AutoCloseable} helps signal that this class contains resources that must be freed.
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 3eb4bde..2fcc4b2 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -55,6 +55,7 @@
  */
 public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage {
 
+    @NonNull
     public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
             @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
         return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
@@ -70,6 +71,7 @@
      * this case only cares about
      * volumeUuid, just fake it rather than having separate method paths.
      */
+    @NonNull
     public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
         return ((ParsedPackage) PackageImpl.forTesting(packageName)
                 .setVolumeUuid(volumeUuid)
@@ -77,11 +79,13 @@
                 .hideAsFinal();
     }
 
+    @NonNull
     @VisibleForTesting
     public static ParsingPackage forTesting(String packageName) {
         return forTesting(packageName, "");
     }
 
+    @NonNull
     @VisibleForTesting
     public static ParsingPackage forTesting(String packageName, String baseCodePath) {
         return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
@@ -568,6 +572,7 @@
         assignDerivedFields();
     }
 
+    @NonNull
     public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
         @Override
         public PackageImpl createFromParcel(Parcel source) {
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 b619a9d..919ed5f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3349,13 +3349,15 @@
     }
 
     @Override
-    public void registerAttributionSource(@NonNull AttributionSource source) {
-        mAttributionSourceRegistry.registerAttributionSource(source);
+    public void registerAttributionSource(@NonNull AttributionSourceState source) {
+        mAttributionSourceRegistry
+                .registerAttributionSource(new AttributionSource(source));
     }
 
     @Override
-    public boolean isRegisteredAttributionSource(@NonNull AttributionSource source) {
-        return mAttributionSourceRegistry.isRegisteredAttributionSource(source);
+    public boolean isRegisteredAttributionSource(@NonNull AttributionSourceState source) {
+        return mAttributionSourceRegistry
+                .isRegisteredAttributionSource(new AttributionSource(source));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index fad0aef..ef21543 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -31,8 +31,7 @@
 import java.util.stream.Collectors;
 
 /**
- * For use by {@link PackageSetting} to maintain functionality that used to exist in
- * {@link PackageParser.Package}.
+ * For use by {@link PackageSetting} to maintain functionality that used to exist in PackageParser.
  *
  * It is assumed that anything inside the package was not cached or written to disk, so none of
  * these fields are either. They must be set on every boot from other state on the device.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e7636fc..75b66b3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3029,7 +3029,8 @@
 
     @Override
     public void onKeyguardOccludedChangedLw(boolean occluded) {
-        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()
+                && !WindowManagerService.sEnableShellTransitions) {
             mPendingKeyguardOccluded = occluded;
             mKeyguardOccludedChanged = true;
         } else {
@@ -3853,9 +3854,13 @@
         }
         mCameraGestureTriggered = false;
         final MutableBoolean outLaunched = new MutableBoolean(false);
-        mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
+        final boolean intercept =
+                mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
         if (!outLaunched.value) {
-            return false;
+            // If GestureLauncherService intercepted the power key, but didn't launch camera app,
+            // we should still return the intercept result. This prevents the single key gesture
+            // detector from processing the power key later on.
+            return intercept;
         }
         mCameraGestureTriggered = true;
         if (mRequestedOrSleepingDefaultDisplay) {
@@ -4255,6 +4260,7 @@
                                     pmWakeReason)) + ")");
         }
 
+        mActivityTaskManagerInternal.notifyWakingUp();
         mDefaultDisplayPolicy.setAwake(true);
 
         // Since goToSleep performs these functions synchronously, we must
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 855a1cc..051f555 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -276,4 +276,4 @@
     public void dump(String prefix, PrintWriter pw) {
         mKeyguardStateMonitor.dump(prefix, pw);
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7555a7f..c91d8de 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -96,6 +96,7 @@
     private static final int MSG_BROADCAST_ENHANCED_PREDICTION = 4;
     private static final int MSG_PROFILE_TIMED_OUT = 5;
     private static final int MSG_WIRED_CHARGING_STARTED = 6;
+    private static final int MSG_SCREEN_POLICY = 7;
 
     private static final long[] CHARGING_VIBRATION_TIME = {
             40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
@@ -120,6 +121,7 @@
     private final SuspendBlocker mSuspendBlocker;
     private final WindowManagerPolicy mPolicy;
     private final FaceDownDetector mFaceDownDetector;
+    private final ScreenUndimDetector mScreenUndimDetector;
     private final ActivityManagerInternal mActivityManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
     private final InputMethodManagerInternal mInputMethodManagerInternal;
@@ -167,13 +169,14 @@
 
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
             SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-            FaceDownDetector faceDownDetector) {
+            FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
         mContext = context;
         mBatteryStats = batteryStats;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mSuspendBlocker = suspendBlocker;
         mPolicy = policy;
         mFaceDownDetector = faceDownDetector;
+        mScreenUndimDetector = screenUndimDetector;
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
@@ -620,6 +623,22 @@
     }
 
     /**
+     * Called when the screen policy changes.
+     */
+    public void onScreenPolicyUpdate(int newPolicy) {
+        if (DEBUG) {
+            Slog.d(TAG, "onScreenPolicyUpdate: newPolicy=" + newPolicy);
+        }
+
+        synchronized (mLock) {
+            Message msg = mHandler.obtainMessage(MSG_SCREEN_POLICY);
+            msg.arg1 = newPolicy;
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
      * Dumps data for bugreports.
      *
      * @param pw The stream to print to.
@@ -659,6 +678,7 @@
         tm.notifyUserActivity();
         mPolicy.userActivity();
         mFaceDownDetector.userActivity(event);
+        mScreenUndimDetector.userActivity();
     }
 
     void postEnhancedDischargePredictionBroadcast(long delayMs) {
@@ -812,6 +832,10 @@
         mSuspendBlocker.release();
     }
 
+    private void screenPolicyChanging(int screenPolicy) {
+        mScreenUndimDetector.recordScreenPolicy(screenPolicy);
+    }
+
     private void lockProfile(@UserIdInt int userId) {
         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
     }
@@ -852,6 +876,9 @@
                 case MSG_WIRED_CHARGING_STARTED:
                     showWiredChargingStarted(msg.arg1);
                     break;
+                case MSG_SCREEN_POLICY:
+                    screenPolicyChanging(msg.arg1);
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c39b5da..218ab78 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -273,6 +273,7 @@
     private final BatterySavingStats mBatterySavingStats;
     private final AttentionDetector mAttentionDetector;
     private final FaceDownDetector mFaceDownDetector;
+    private final ScreenUndimDetector mScreenUndimDetector;
     private final BinderService mBinderService;
     private final LocalService mLocalService;
     private final NativeWrapper mNativeWrapper;
@@ -837,9 +838,10 @@
     static class Injector {
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
             return new Notifier(
-                    looper, context, batteryStats, suspendBlocker, policy, faceDownDetector);
+                    looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
+                    screenUndimDetector);
         }
 
         SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -960,6 +962,7 @@
                 mInjector.createAmbientDisplaySuppressionController(context);
         mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
         mFaceDownDetector = new FaceDownDetector(this::onFlip);
+        mScreenUndimDetector = new ScreenUndimDetector();
 
         mBatterySavingStats = new BatterySavingStats(mLock);
         mBatterySaverPolicy =
@@ -1152,7 +1155,7 @@
             mBatteryStats = BatteryStatsService.getService();
             mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
-                    mPolicy, mFaceDownDetector);
+                    mPolicy, mFaceDownDetector, mScreenUndimDetector);
 
             mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
                     mInjector.createSuspendBlocker(
@@ -1187,6 +1190,7 @@
         mBatterySaverController.systemReady();
         mBatterySaverPolicy.systemReady();
         mFaceDownDetector.systemReady(mContext);
+        mScreenUndimDetector.systemReady(mContext);
 
         // Register for settings changes.
         resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -3192,6 +3196,7 @@
 
                 final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
                         displayPowerRequest, mRequestWaitForNegativeProximity);
+                mNotifier.onScreenPolicyUpdate(displayPowerRequest.policy);
 
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
diff --git a/services/core/java/com/android/server/power/ScreenUndimDetector.java b/services/core/java/com/android/server/power/ScreenUndimDetector.java
new file mode 100644
index 0000000..951bc1f
--- /dev/null
+++ b/services/core/java/com/android/server/power/ScreenUndimDetector.java
@@ -0,0 +1,297 @@
+/*
+ * 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.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Detects when user manually undims the screen (x times) and acquires a wakelock to keep the screen
+ * on temporarily (without changing the screen timeout setting).
+ */
+public class ScreenUndimDetector {
+    private static final String TAG = "ScreenUndimDetector";
+    private static final boolean DEBUG = false;
+
+    private static final String UNDIM_DETECTOR_WAKE_LOCK = "UndimDetectorWakeLock";
+
+    /** DeviceConfig flag: is keep screen on feature enabled. */
+    static final String KEY_KEEP_SCREEN_ON_ENABLED = "keep_screen_on_enabled";
+    private static final boolean DEFAULT_KEEP_SCREEN_ON_ENABLED = true;
+    private static final int OUTCOME_POWER_BUTTON =
+            FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__POWER_BUTTON;
+    private static final int OUTCOME_TIMEOUT =
+            FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME__TIMEOUT;
+    private boolean mKeepScreenOnEnabled;
+
+    /** DeviceConfig flag: how long should we keep the screen on. */
+    @VisibleForTesting
+    static final String KEY_KEEP_SCREEN_ON_FOR_MILLIS = "keep_screen_on_for_millis";
+    @VisibleForTesting
+    static final long DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS = TimeUnit.MINUTES.toMillis(10);
+    private long mKeepScreenOnForMillis;
+
+    /** DeviceConfig flag: how many user undims required to trigger keeping the screen on. */
+    @VisibleForTesting
+    static final String KEY_UNDIMS_REQUIRED = "undims_required";
+    @VisibleForTesting
+    static final int DEFAULT_UNDIMS_REQUIRED = 2;
+    private int mUndimsRequired;
+
+    /**
+     * DeviceConfig flag: what is the maximum duration between undims to still consider them
+     * consecutive.
+     */
+    @VisibleForTesting
+    static final String KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS =
+            "max_duration_between_undims_millis";
+    @VisibleForTesting
+    static final long DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS = TimeUnit.MINUTES.toMillis(5);
+    private long mMaxDurationBetweenUndimsMillis;
+
+    @VisibleForTesting
+    PowerManager.WakeLock mWakeLock;
+
+    @VisibleForTesting
+    int mCurrentScreenPolicy;
+    @VisibleForTesting
+    int mUndimCounter = 0;
+    @VisibleForTesting
+    long mUndimCounterStartedMillis;
+    private long mUndimOccurredTime = -1;
+    private long mInteractionAfterUndimTime = -1;
+    private InternalClock mClock;
+
+    public ScreenUndimDetector() {
+        mClock = new InternalClock();
+    }
+
+    ScreenUndimDetector(InternalClock clock) {
+        mClock = clock;
+    }
+
+    static class InternalClock {
+        public long getCurrentTime() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
+
+    /** Should be called in parent's systemReady() */
+    public void systemReady(Context context) {
+        readValuesFromDeviceConfig();
+        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                context.getMainExecutor(),
+                (properties) -> onDeviceConfigChange(properties.getKeyset()));
+
+        final PowerManager powerManager = context.getSystemService(PowerManager.class);
+        mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
+                        | PowerManager.ON_AFTER_RELEASE,
+                UNDIM_DETECTOR_WAKE_LOCK);
+    }
+
+    /**
+     * Launches a message that figures out the screen transitions and detects user undims. Must be
+     * called by the parent that is trying to update the screen policy.
+     */
+    public void recordScreenPolicy(int newPolicy) {
+        if (newPolicy == mCurrentScreenPolicy) {
+            return;
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG,
+                    "Screen policy transition: " + mCurrentScreenPolicy + " -> " + newPolicy);
+        }
+
+        // update the current policy with the new one immediately so we don't accidentally get
+        // into a loop (which is possible if the switch below triggers a new policy).
+        final int currentPolicy = mCurrentScreenPolicy;
+        mCurrentScreenPolicy = newPolicy;
+
+        if (!mKeepScreenOnEnabled) {
+            return;
+        }
+
+        switch (currentPolicy) {
+            case POLICY_DIM:
+                if (newPolicy == POLICY_BRIGHT) {
+                    final long now = mClock.getCurrentTime();
+                    final long timeElapsedSinceFirstUndim = now - mUndimCounterStartedMillis;
+                    if (timeElapsedSinceFirstUndim >= mMaxDurationBetweenUndimsMillis) {
+                        reset();
+                    }
+                    if (mUndimCounter == 0) {
+                        mUndimCounterStartedMillis = now;
+                    }
+
+                    mUndimCounter++;
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "User undim, counter=" + mUndimCounter
+                                + " (required=" + mUndimsRequired + ")"
+                                + ", timeElapsedSinceFirstUndim=" + timeElapsedSinceFirstUndim
+                                + " (max=" + mMaxDurationBetweenUndimsMillis + ")");
+                    }
+                    if (mUndimCounter >= mUndimsRequired) {
+                        reset();
+                        if (DEBUG) {
+                            Slog.d(TAG, "Acquiring a wake lock for " + mKeepScreenOnForMillis);
+                        }
+                        if (mWakeLock != null) {
+                            mUndimOccurredTime = mClock.getCurrentTime();
+                            mWakeLock.acquire(mKeepScreenOnForMillis);
+                        }
+                    }
+                } else {
+                    if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+                        checkAndLogUndim(OUTCOME_TIMEOUT);
+                    }
+                    reset();
+                }
+                break;
+            case POLICY_BRIGHT:
+                if (newPolicy == POLICY_OFF || newPolicy == POLICY_DOZE) {
+                    checkAndLogUndim(OUTCOME_POWER_BUTTON);
+                }
+                if (newPolicy != POLICY_DIM) {
+                    reset();
+                }
+                break;
+        }
+    }
+
+    @VisibleForTesting
+    void reset() {
+        if (DEBUG) {
+            Slog.d(TAG, "Resetting the undim detector");
+        }
+        mUndimCounter = 0;
+        mUndimCounterStartedMillis = 0;
+        if (mWakeLock != null && mWakeLock.isHeld()) {
+            mWakeLock.release();
+        }
+    }
+
+    private boolean readKeepScreenOnNotificationEnabled() {
+        return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_ENABLED,
+                DEFAULT_KEEP_SCREEN_ON_ENABLED);
+    }
+
+    private long readKeepScreenOnForMillis() {
+        return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_FOR_MILLIS,
+                DEFAULT_KEEP_SCREEN_ON_FOR_MILLIS);
+    }
+
+    private int readUndimsRequired() {
+        int undimsRequired = DeviceConfig.getInt(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                DEFAULT_UNDIMS_REQUIRED);
+
+        if (undimsRequired < 1 || undimsRequired > 5) {
+            Slog.e(TAG, "Provided undimsRequired=" + undimsRequired
+                    + " is not allowed [1, 5]; using the default=" + DEFAULT_UNDIMS_REQUIRED);
+            return DEFAULT_UNDIMS_REQUIRED;
+        }
+
+        return undimsRequired;
+    }
+
+    private long readMaxDurationBetweenUndimsMillis() {
+        return DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+                DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS);
+    }
+
+    private void onDeviceConfigChange(@NonNull Set<String> keys) {
+        for (String key : keys) {
+            Slog.i(TAG, "onDeviceConfigChange; key=" + key);
+            switch (key) {
+                case KEY_KEEP_SCREEN_ON_ENABLED:
+                case KEY_KEEP_SCREEN_ON_FOR_MILLIS:
+                case KEY_UNDIMS_REQUIRED:
+                case KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS:
+                    readValuesFromDeviceConfig();
+                    return;
+                default:
+                    Slog.i(TAG, "Ignoring change on " + key);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void readValuesFromDeviceConfig() {
+        mKeepScreenOnEnabled = readKeepScreenOnNotificationEnabled();
+        mKeepScreenOnForMillis = readKeepScreenOnForMillis();
+        mUndimsRequired = readUndimsRequired();
+        mMaxDurationBetweenUndimsMillis = readMaxDurationBetweenUndimsMillis();
+
+        Slog.i(TAG, "readValuesFromDeviceConfig():"
+                + "\nmKeepScreenOnForMillis=" + mKeepScreenOnForMillis
+                + "\nmKeepScreenOnNotificationEnabled=" + mKeepScreenOnEnabled
+                + "\nmUndimsRequired=" + mUndimsRequired);
+
+    }
+
+    /**
+     * The user interacted with the screen after an undim, indicating the phone is in use.
+     * We use this event for logging.
+     */
+    public void userActivity() {
+        if (mUndimOccurredTime != 1 && mInteractionAfterUndimTime == -1) {
+            mInteractionAfterUndimTime = mClock.getCurrentTime();
+        }
+    }
+
+    /**
+     * Checks and logs if an undim occurred.
+     *
+     * A log will occur if an undim seems to have resulted in a timeout or a direct screen off such
+     * as from a power button. Some outcomes may not be correctly assigned to a
+     * TIMEOUT_AUTO_EXTENDED_REPORTED__OUTCOME value.
+     */
+    private void checkAndLogUndim(int outcome) {
+        if (mUndimOccurredTime != -1) {
+            long now = mClock.getCurrentTime();
+            FrameworkStatsLog.write(FrameworkStatsLog.TIMEOUT_AUTO_EXTENDED_REPORTED,
+                    outcome,
+                    /* time_to_outcome_millis=*/  now - mUndimOccurredTime,
+                    /* time_to_first_interaction_millis= */
+                    mInteractionAfterUndimTime != -1 ? now - mInteractionAfterUndimTime : -1
+            );
+            mUndimOccurredTime = -1;
+            mInteractionAfterUndimTime = -1;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 6014d0c..2491565d 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -255,7 +255,11 @@
     private boolean checkTidValid(int uid, int tgid, int [] tids) {
         // Make sure all tids belongs to the same UID (including isolated UID),
         // tids can belong to different application processes.
-        List<Integer> eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+        List<Integer> eligiblePids = null;
+        // To avoid deadlock, do not call into AMS if the call is from system.
+        if (uid != Process.SYSTEM_UID) {
+            eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+        }
         if (eligiblePids == null) {
             eligiblePids = new ArrayList<>();
         }
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index c8e3648..c7e7784 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -143,10 +143,10 @@
             int rollbackId, int appId, String seInfo, int flags) {
         if (packageRollbackInfo.isApex()) {
             switch (packageRollbackInfo.getRollbackDataPolicy()) {
-                case PackageManager.RollbackDataPolicy.WIPE:
+                case PackageManager.ROLLBACK_DATA_POLICY_WIPE:
                     // TODO: Implement WIPE for apex CE data
                     break;
-                case PackageManager.RollbackDataPolicy.RESTORE:
+                case PackageManager.ROLLBACK_DATA_POLICY_RESTORE:
                     // For APEX, only restore of CE may be done here.
                     if ((flags & Installer.FLAG_STORAGE_CE) != 0) {
                         mApexManager.restoreCeData(
@@ -160,11 +160,11 @@
             // APK
             try {
                 switch (packageRollbackInfo.getRollbackDataPolicy()) {
-                    case PackageManager.RollbackDataPolicy.WIPE:
+                    case PackageManager.ROLLBACK_DATA_POLICY_WIPE:
                         mInstaller.clearAppData(null, packageRollbackInfo.getPackageName(),
                                 userId, flags, 0);
                         break;
-                    case PackageManager.RollbackDataPolicy.RESTORE:
+                    case PackageManager.ROLLBACK_DATA_POLICY_RESTORE:
 
                         mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(),
                                 appId, seInfo, userId, rollbackId, flags);
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 7bf3478..38e6b28 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -438,7 +438,7 @@
         for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
             if (pkgRollbackInfo.getPackageName().equals(packageName)) {
                 if (pkgRollbackInfo.getRollbackDataPolicy()
-                        == PackageManager.RollbackDataPolicy.RESTORE) {
+                        == PackageManager.ROLLBACK_DATA_POLICY_RESTORE) {
                     dataHelper.snapshotAppData(info.getRollbackId(), pkgRollbackInfo, userIds);
                     addAll(pkgRollbackInfo.getSnapshottedUsers(), userIds);
                     RollbackStore.saveRollback(this);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index f7ed000..a564624 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -800,7 +800,7 @@
         // precedence only when it is not the default (i.e. RESTORE). We will remove
         // SessionParams#setEnableRollback(boolean, int) and related code when Play has migrated to
         // using the manifest to specify the policy.
-        if (manifestPolicy != PackageManager.RollbackDataPolicy.RESTORE) {
+        if (manifestPolicy != PackageManager.ROLLBACK_DATA_POLICY_RESTORE) {
             return manifestPolicy;
         }
         return sessionPolicy;
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 6b783f7..2cfc785 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -447,7 +447,7 @@
 
         // Backward compatibility: no such field for old versions.
         final int rollbackDataPolicy = json.optInt("rollbackDataPolicy",
-                PackageManager.RollbackDataPolicy.RESTORE);
+                PackageManager.ROLLBACK_DATA_POLICY_RESTORE);
 
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
                 pendingBackups, pendingRestores, isApex, isApkInApex, snapshottedUsers,
diff --git a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
index 3ca8a5a..87b28db 100644
--- a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
+++ b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
@@ -62,7 +62,7 @@
  * not require callers to hold this permission is rejected (2) a service permission - any service
  * whose package does not hold this permission is rejected.
  */
-public class CurrentUserServiceSupplier extends BroadcastReceiver implements
+public final class CurrentUserServiceSupplier extends BroadcastReceiver implements
         ServiceSupplier<CurrentUserServiceSupplier.BoundServiceInfo> {
 
     private static final String TAG = "CurrentUserServiceSupplier";
@@ -144,6 +144,53 @@
         }
     }
 
+    /**
+     * Creates an instance using package details retrieved from config.
+     *
+     * @see #create(Context, String, String, String, String)
+     */
+    public static CurrentUserServiceSupplier createFromConfig(Context context, String action,
+            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
+        String explicitPackage = retrieveExplicitPackage(context, enableOverlayResId,
+                nonOverlayPackageResId);
+        return CurrentUserServiceSupplier.create(context, action, explicitPackage,
+                /*callerPermission=*/null, /*servicePermission=*/null);
+    }
+
+    /**
+     * Creates an instance with the specific service details and permission requirements.
+     *
+     * @param context the context the supplier is to use
+     * @param action the action the service must declare in its intent-filter
+     * @param explicitPackage the package of the service, or {@code null} if the package of the
+     *     service is not constrained
+     * @param callerPermission a permission that the service forces callers (i.e.
+     *     ServiceWatcher/system server) to hold, or {@code null} if there isn't one
+     * @param servicePermission a permission that the service package should hold, or {@code null}
+     *     if there isn't one
+     */
+    public static CurrentUserServiceSupplier create(Context context, String action,
+            @Nullable String explicitPackage, @Nullable String callerPermission,
+            @Nullable String servicePermission) {
+        boolean matchSystemAppsOnly = true;
+        return new CurrentUserServiceSupplier(context, action,
+                explicitPackage, callerPermission, servicePermission, matchSystemAppsOnly);
+    }
+
+    /**
+     * Creates an instance like {@link #create} except it allows connection to services that are not
+     * supplied by system packages. Only intended for use during tests.
+     *
+     * @see #create(Context, String, String, String, String)
+     */
+    public static CurrentUserServiceSupplier createUnsafeForTestsOnly(Context context,
+            String action, @Nullable String explicitPackage, @Nullable String callerPermission,
+            @Nullable String servicePermission) {
+        boolean matchSystemAppsOnly = false;
+        return new CurrentUserServiceSupplier(context, action,
+                explicitPackage, callerPermission, servicePermission, matchSystemAppsOnly);
+    }
+
     private static @Nullable String retrieveExplicitPackage(Context context,
             @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
         Resources resources = context.getResources();
@@ -162,31 +209,14 @@
     private final @Nullable String mCallerPermission;
     // a permission that the service package should hold
     private final @Nullable String mServicePermission;
+    // whether to use MATCH_SYSTEM_ONLY in queries
+    private final boolean mMatchSystemAppsOnly;
 
     private volatile ServiceChangedListener mListener;
 
-    public CurrentUserServiceSupplier(Context context, String action) {
-        this(context, action, null, null, null);
-    }
-
-    public CurrentUserServiceSupplier(Context context, String action,
-            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
-        this(context, action,
-                retrieveExplicitPackage(context, enableOverlayResId, nonOverlayPackageResId), null,
-                null);
-    }
-
-    public CurrentUserServiceSupplier(Context context, String action,
-            @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId,
-            @Nullable String callerPermission, @Nullable String servicePermission) {
-        this(context, action,
-                retrieveExplicitPackage(context, enableOverlayResId, nonOverlayPackageResId),
-                callerPermission, servicePermission);
-    }
-
-    public CurrentUserServiceSupplier(Context context, String action,
+    private CurrentUserServiceSupplier(Context context, String action,
             @Nullable String explicitPackage, @Nullable String callerPermission,
-            @Nullable String servicePermission) {
+            @Nullable String servicePermission, boolean matchSystemAppsOnly) {
         mContext = context;
         mActivityManager = Objects.requireNonNull(
                 LocalServices.getService(ActivityManagerInternal.class));
@@ -198,13 +228,18 @@
 
         mCallerPermission = callerPermission;
         mServicePermission = servicePermission;
+        mMatchSystemAppsOnly = matchSystemAppsOnly;
     }
 
     @Override
     public boolean hasMatchingService() {
+        int intentQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+        if (mMatchSystemAppsOnly) {
+            intentQueryFlags |= MATCH_SYSTEM_ONLY;
+        }
         List<ResolveInfo> resolveInfos = mContext.getPackageManager()
                 .queryIntentServicesAsUser(mIntent,
-                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
+                        intentQueryFlags,
                         UserHandle.USER_SYSTEM);
         return !resolveInfos.isEmpty();
     }
@@ -234,11 +269,15 @@
     public BoundServiceInfo getServiceInfo() {
         BoundServiceInfo bestServiceInfo = null;
 
-        // only allow privileged services in the correct direct boot state to match
+        // only allow services in the correct direct boot state to match
+        int intentQueryFlags = MATCH_DIRECT_BOOT_AUTO | GET_META_DATA;
+        if (mMatchSystemAppsOnly) {
+            intentQueryFlags |= MATCH_SYSTEM_ONLY;
+        }
         int currentUserId = mActivityManager.getCurrentUserId();
         List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
                 mIntent,
-                GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
+                intentQueryFlags,
                 currentUserId);
         for (ResolveInfo resolveInfo : resolveInfos) {
             ServiceInfo service = Objects.requireNonNull(resolveInfo.serviceInfo);
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
index 2be8e35..5828130 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java
@@ -46,19 +46,12 @@
 public final class ServiceConfigAccessor {
 
     @StringDef(prefix = "PROVIDER_MODE_",
-            value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
+            value = { PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
     @interface ProviderMode {}
 
     /**
-     * The "simulated" provider mode.
-     * For use with {@link #getPrimaryLocationTimeZoneProviderMode()} and {@link
-     * #getSecondaryLocationTimeZoneProviderMode()}.
-     */
-    public static final @ProviderMode String PROVIDER_MODE_SIMULATED = "simulated";
-
-    /**
      * The "disabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()}
      * and {@link #getSecondaryLocationTimeZoneProviderMode()}.
      */
@@ -110,6 +103,47 @@
 
     @NonNull private final ServerFlags mServerFlags;
 
+    /**
+     * The mode to use for the primary location time zone provider in a test. Setting this
+     * disables some permission checks.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test provider accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    @Nullable
+    private String mTestPrimaryLocationTimeZoneProviderMode;
+
+    /**
+     * The package name to use for the primary location time zone provider in a test.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test provider accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    @Nullable
+    private String mTestPrimaryLocationTimeZoneProviderPackageName;
+
+    /**
+     * See {@link #mTestPrimaryLocationTimeZoneProviderMode}; this is the equivalent for the
+     * secondary provider.
+     */
+    @Nullable
+    private String mTestSecondaryLocationTimeZoneProviderMode;
+
+    /**
+     * See {@link #mTestPrimaryLocationTimeZoneProviderPackageName}; this is the equivalent for the
+     * secondary provider.
+     */
+    @Nullable
+    private String mTestSecondaryLocationTimeZoneProviderPackageName;
+
+    /**
+     * Whether to record state changes for tests.
+     * This state is volatile: it is never written to storage / never survives a reboot. This is to
+     * avoid a test state accidentally being left configured on a device.
+     * See also {@link #resetVolatileTestConfig()}.
+     */
+    private boolean mRecordProviderStateChanges;
+
     private ServiceConfigAccessor(@NonNull Context context) {
         mContext = Objects.requireNonNull(context);
 
@@ -200,23 +234,98 @@
                 defaultEnabled);
     }
 
+    /** Returns the package name of the app hosting the primary location time zone provider. */
     @NonNull
     public String getPrimaryLocationTimeZoneProviderPackageName() {
+        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestPrimaryLocationTimeZoneProviderPackageName;
+        }
         return mContext.getResources().getString(
                 R.string.config_primaryLocationTimeZoneProviderPackageName);
     }
 
+    /**
+     * Sets the package name of the app hosting the primary location time zone provider for tests.
+     * Setting a {@code null} value means the provider is to be disabled.
+     * The values are reset with {@link #resetVolatileTestConfig()}.
+     */
+    public void setTestPrimaryLocationTimeZoneProviderPackageName(
+            @Nullable String testPrimaryLocationTimeZoneProviderPackageName) {
+        mTestPrimaryLocationTimeZoneProviderPackageName =
+                testPrimaryLocationTimeZoneProviderPackageName;
+        mTestPrimaryLocationTimeZoneProviderMode =
+                mTestPrimaryLocationTimeZoneProviderPackageName == null
+                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+    }
+
+    /**
+     * Returns {@code true} if the usual permission checks are to be bypassed for the primary
+     * provider. Returns {@code true} only if {@link
+     * #setTestPrimaryLocationTimeZoneProviderPackageName} has been called.
+     */
+    public boolean isTestPrimaryLocationTimeZoneProvider() {
+        return mTestPrimaryLocationTimeZoneProviderMode != null;
+    }
+
+    /** Returns the package name of the app hosting the secondary location time zone provider. */
     @NonNull
     public String getSecondaryLocationTimeZoneProviderPackageName() {
+        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestSecondaryLocationTimeZoneProviderPackageName;
+        }
         return mContext.getResources().getString(
                 R.string.config_secondaryLocationTimeZoneProviderPackageName);
     }
 
     /**
-     * Returns {@code true} if the primary location time zone provider can be used.
+     * Sets the package name of the app hosting the secondary location time zone provider for tests.
+     * Setting a {@code null} value means the provider is to be disabled.
+     * The values are reset with {@link #resetVolatileTestConfig()}.
+     */
+    public void setTestSecondaryLocationTimeZoneProviderPackageName(
+            @Nullable String testSecondaryLocationTimeZoneProviderPackageName) {
+        mTestSecondaryLocationTimeZoneProviderPackageName =
+                testSecondaryLocationTimeZoneProviderPackageName;
+        mTestSecondaryLocationTimeZoneProviderMode =
+                mTestSecondaryLocationTimeZoneProviderPackageName == null
+                        ? PROVIDER_MODE_DISABLED : PROVIDER_MODE_ENABLED;
+    }
+
+    /**
+     * Returns {@code true} if the usual permission checks are to be bypassed for the secondary
+     * provider. Returns {@code true} only if {@link
+     * #setTestSecondaryLocationTimeZoneProviderPackageName} has been called.
+     */
+    public boolean isTestSecondaryLocationTimeZoneProvider() {
+        return mTestSecondaryLocationTimeZoneProviderMode != null;
+    }
+
+    /**
+     * Enables/disables the state recording mode for tests. The value is reset with {@link
+     * #resetVolatileTestConfig()}.
+     */
+    public void setRecordProviderStateChanges(boolean enabled) {
+        mRecordProviderStateChanges = enabled;
+    }
+
+    /**
+     * Returns {@code true} if providers are expected to record their state changes for tests.
+     */
+    public boolean getRecordProviderStateChanges() {
+        return mRecordProviderStateChanges;
+    }
+
+    /**
+     * Returns the mode for the primary location time zone provider.
      */
     @NonNull
     public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() {
+        if (mTestPrimaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestPrimaryLocationTimeZoneProviderMode;
+        }
         return mServerFlags.getOptionalString(
                 ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
                 .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig());
@@ -230,9 +339,13 @@
     }
 
     /**
-     * Returns the mode for the secondary location time zone provider can be used.
+     * Returns the mode for the secondary location time zone provider.
      */
     public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() {
+        if (mTestSecondaryLocationTimeZoneProviderMode != null) {
+            // In test mode: use the test setting value.
+            return mTestSecondaryLocationTimeZoneProviderMode;
+        }
         return mServerFlags.getOptionalString(
                 ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE)
                 .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig());
@@ -298,6 +411,15 @@
                 DEFAULT_PROVIDER_UNCERTAINTY_DELAY);
     }
 
+    /** Clears all in-memory test config. */
+    public void resetVolatileTestConfig() {
+        mTestPrimaryLocationTimeZoneProviderPackageName = null;
+        mTestPrimaryLocationTimeZoneProviderMode = null;
+        mTestSecondaryLocationTimeZoneProviderPackageName = null;
+        mTestSecondaryLocationTimeZoneProviderMode = null;
+        mRecordProviderStateChanges = false;
+    }
+
     private boolean getConfigBoolean(int providerEnabledConfigId) {
         Resources resources = mContext.getResources();
         return resources.getBoolean(providerEnabledConfigId);
diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
index 59df6ff..9d340e4 100644
--- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
@@ -26,7 +26,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.RemoteCallback;
 import android.util.IndentingPrintWriter;
 
 import java.time.Duration;
@@ -45,9 +44,10 @@
             @NonNull ProviderMetricsLogger providerMetricsLogger,
             @NonNull ThreadingDomain threadingDomain,
             @NonNull String providerName,
-            @NonNull LocationTimeZoneProviderProxy proxy) {
+            @NonNull LocationTimeZoneProviderProxy proxy,
+            boolean recordStateChanges) {
         super(providerMetricsLogger, threadingDomain, providerName,
-                new ZoneInfoDbTimeZoneProviderEventPreProcessor());
+                new ZoneInfoDbTimeZoneProviderEventPreProcessor(), recordStateChanges);
         mProxy = Objects.requireNonNull(proxy);
     }
 
@@ -125,16 +125,6 @@
         mProxy.setRequest(request);
     }
 
-    /**
-     * Passes the supplied test command to the current proxy.
-     */
-    @Override
-    void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
-        mThreadingDomain.assertCurrentThread();
-
-        mProxy.handleTestCommand(testCommand, callback);
-    }
-
     @Override
     public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
         synchronized (mSharedLock) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
index b1019f3..76ef958 100644
--- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java
@@ -33,7 +33,6 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.RemoteCallback;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
@@ -590,41 +589,14 @@
     }
 
     /**
-     * Passes a test command to the specified provider. If the provider name does not match a
-     * known provider, then the command is logged and discarded.
+     * Clears recorded provider state changes (for use during tests).
      */
-    void handleProviderTestCommand(
-            @IntRange(from = 0, to = 1) int providerIndex, @NonNull TestCommand testCommand,
-            @Nullable RemoteCallback callback) {
-        mThreadingDomain.assertCurrentThread();
-
-        LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerIndex);
-        if (targetProvider == null) {
-            warnLog("Unable to process test command:"
-                    + " providerIndex=" + providerIndex + ", testCommand=" + testCommand);
-            return;
-        }
-
-        synchronized (mSharedLock) {
-            try {
-                targetProvider.handleTestCommand(testCommand, callback);
-            } catch (Exception e) {
-                warnLog("Unable to process test command:"
-                        + " providerIndex=" + providerIndex + ", testCommand=" + testCommand, e);
-            }
-        }
-    }
-
-    /**
-     * Sets whether the controller should record provider state changes for later dumping via
-     * {@link #getStateForTests()}.
-     */
-    void setProviderStateRecordingEnabled(boolean enabled) {
+    void clearRecordedProviderStates() {
         mThreadingDomain.assertCurrentThread();
 
         synchronized (mSharedLock) {
-            mPrimaryProvider.setStateChangeRecordingEnabled(enabled);
-            mSecondaryProvider.setStateChangeRecordingEnabled(enabled);
+            mPrimaryProvider.clearRecordedStates();
+            mSecondaryProvider.clearRecordedStates();
         }
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index d8d44d4..8dbc520 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -19,16 +19,13 @@
 import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
 
 import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
-import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.RemoteCallback;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.service.timezone.TimeZoneProviderService;
@@ -50,9 +47,6 @@
 import java.io.PrintWriter;
 import java.time.Duration;
 import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * A service class that acts as a container for the {@link LocationTimeZoneProviderController},
@@ -70,12 +64,6 @@
  * one indicated by {@link ThreadingDomain}. Because methods like {@link #dump} can be invoked on
  * another thread, the service and its related objects must still be thread-safe.
  *
- * <p>For testing / reproduction of bugs, it is possible to put providers into "simulation
- * mode" where the real binder clients are replaced by {@link
- * SimulatedLocationTimeZoneProviderProxy}. This means that the real client providers are never
- * bound (ensuring no real location events will be received) and simulated events / behaviors
- * can be injected via the command line.
- *
  * <p>See {@code adb shell cmd location_time_zone_manager help}" for details and more options.
  */
 public class LocationTimeZoneManagerService extends Binder {
@@ -247,6 +235,36 @@
         }
     }
 
+    /**
+     * Starts the service with fake provider package names configured for tests. The config is
+     * cleared when the service next stops.
+     *
+     * <p>Because this method posts work to the {@code mThreadingDomain} thread and waits for
+     * completion, it cannot be called from the {@code mThreadingDomain} thread.
+     */
+    void startWithTestProviders(@Nullable String testPrimaryProviderPackageName,
+            @Nullable String testSecondaryProviderPackageName,
+            boolean recordProviderStateChanges) {
+        enforceManageTimeZoneDetectorPermission();
+
+        if (testPrimaryProviderPackageName == null && testSecondaryProviderPackageName == null) {
+            throw new IllegalArgumentException("One or both test package names must be provided.");
+        }
+
+        mThreadingDomain.postAndWait(() -> {
+            synchronized (mSharedLock) {
+                stopOnDomainThread();
+
+                mServiceConfigAccessor.setTestPrimaryLocationTimeZoneProviderPackageName(
+                        testPrimaryProviderPackageName);
+                mServiceConfigAccessor.setTestSecondaryLocationTimeZoneProviderPackageName(
+                        testSecondaryProviderPackageName);
+                mServiceConfigAccessor.setRecordProviderStateChanges(recordProviderStateChanges);
+                startOnDomainThread();
+            }
+        }, BLOCKING_OP_WAIT_DURATION_MILLIS);
+    }
+
     private void startOnDomainThread() {
         mThreadingDomain.assertCurrentThread();
 
@@ -295,6 +313,9 @@
                 mLocationTimeZoneDetectorController = null;
                 mEnvironment.destroy();
                 mEnvironment = null;
+
+                // Clear test state so it won't be used the next time the service is started.
+                mServiceConfigAccessor.resetVolatileTestConfig();
             }
         }
     }
@@ -307,14 +328,14 @@
                 this, in, out, err, args, callback, resultReceiver);
     }
 
-    /** Sets this service into provider state recording mode for tests. */
-    void setProviderStateRecordingEnabled(boolean enabled) {
+    /** Clears recorded provider state for tests. */
+    void clearRecordedProviderStates() {
         enforceManageTimeZoneDetectorPermission();
 
         mThreadingDomain.postAndWait(() -> {
             synchronized (mSharedLock) {
                 if (mLocationTimeZoneDetectorController != null) {
-                    mLocationTimeZoneDetectorController.setProviderStateRecordingEnabled(enabled);
+                    mLocationTimeZoneDetectorController.clearRecordedProviderStates();
                 }
             }
         }, BLOCKING_OP_WAIT_DURATION_MILLIS);
@@ -344,48 +365,6 @@
         }
     }
 
-    /**
-     * Passes a {@link TestCommand} to the specified provider and waits for the response.
-     */
-    @NonNull
-    Bundle handleProviderTestCommand(@IntRange(from = 0, to = 1) int providerIndex,
-            @NonNull TestCommand testCommand) {
-        enforceManageTimeZoneDetectorPermission();
-
-        // Because this method blocks and posts work to the threading domain thread, it would cause
-        // a deadlock if it were called by the threading domain thread.
-        mThreadingDomain.assertNotCurrentThread();
-
-        AtomicReference<Bundle> resultReference = new AtomicReference<>();
-        CountDownLatch latch = new CountDownLatch(1);
-        RemoteCallback remoteCallback = new RemoteCallback(x -> {
-            resultReference.set(x);
-            latch.countDown();
-        });
-
-        mThreadingDomain.post(() -> {
-            synchronized (mSharedLock) {
-                if (mLocationTimeZoneDetectorController == null) {
-                    remoteCallback.sendResult(null);
-                    return;
-                }
-                mLocationTimeZoneDetectorController.handleProviderTestCommand(
-                        providerIndex, testCommand, remoteCallback);
-            }
-        });
-
-        try {
-            // Wait, but not indefinitely.
-            if (!latch.await(BLOCKING_OP_WAIT_DURATION_MILLIS, TimeUnit.MILLISECONDS)) {
-                throw new RuntimeException("Command did not complete in time");
-            }
-        } catch (InterruptedException e) {
-            throw new AssertionError(e);
-        }
-
-        return resultReference.get();
-    }
-
     @Override
     protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
             @Nullable String[] args) {
@@ -463,7 +442,8 @@
             LocationTimeZoneProviderProxy proxy = createProxy();
             ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);
             return new BinderLocationTimeZoneProvider(
-                    providerMetricsLogger, mThreadingDomain, mName, proxy);
+                    providerMetricsLogger, mThreadingDomain, mName, proxy,
+                    mServiceConfigAccessor.getRecordProviderStateChanges());
         }
 
         @GuardedBy("mSharedLock")
@@ -476,9 +456,7 @@
         @NonNull
         private LocationTimeZoneProviderProxy createProxy() {
             String mode = getMode();
-            if (Objects.equals(mode, PROVIDER_MODE_SIMULATED)) {
-                return new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
-            } else if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) {
+            if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) {
                 return new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
             } else {
                 // mode == PROVIDER_MODE_OVERRIDE_ENABLED (or unknown).
@@ -486,7 +464,7 @@
             }
         }
 
-        /** Returns the mode of the provider. */
+        /** Returns the mode of the provider (enabled/disabled). */
         @NonNull
         private String getMode() {
             if (mIndex == 0) {
@@ -499,10 +477,19 @@
         @NonNull
         private RealLocationTimeZoneProviderProxy createRealProxy() {
             String providerServiceAction = mServiceAction;
+            boolean isTestProvider = isTestProvider();
             String providerPackageName = getPackageName();
             return new RealLocationTimeZoneProviderProxy(
                     mContext, mHandler, mThreadingDomain, providerServiceAction,
-                    providerPackageName);
+                    providerPackageName, isTestProvider);
+        }
+
+        private boolean isTestProvider() {
+            if (mIndex == 0) {
+                return mServiceConfigAccessor.isTestPrimaryLocationTimeZoneProvider();
+            } else {
+                return mServiceConfigAccessor.isTestSecondaryLocationTimeZoneProvider();
+            }
         }
 
         @NonNull
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
index 0f0de50..3488956 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java
@@ -16,11 +16,12 @@
 package com.android.server.timezonedetector.location;
 
 import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
+import static android.app.time.LocationTimeZoneManager.NULL_PACKAGE_NAME_TOKEN;
 import static android.app.time.LocationTimeZoneManager.SERVICE_NAME;
+import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_CLEAR_RECORDED_PROVIDER_STATES;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
-import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
-import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START;
+import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START_WITH_TEST_PROVIDERS;
 import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_STOP;
 import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
 
@@ -31,7 +32,6 @@
 import static com.android.server.timedetector.ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE;
 import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED;
 import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_ENABLED;
-import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
@@ -41,12 +41,12 @@
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_UNKNOWN;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.time.GeolocationTimeZoneSuggestionProto;
 import android.app.time.LocationTimeZoneManagerProto;
 import android.app.time.LocationTimeZoneManagerServiceStateProto;
 import android.app.time.TimeZoneProviderStateProto;
 import android.app.timezonedetector.TimeZoneDetector;
-import android.os.Bundle;
 import android.os.ShellCommand;
 import android.util.IndentingPrintWriter;
 import android.util.proto.ProtoOutputStream;
@@ -79,14 +79,14 @@
             case SHELL_COMMAND_START: {
                 return runStart();
             }
+            case SHELL_COMMAND_START_WITH_TEST_PROVIDERS: {
+                return runStartWithTestProviders();
+            }
             case SHELL_COMMAND_STOP: {
                 return runStop();
             }
-            case SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND: {
-                return runSendProviderTestCommand();
-            }
-            case SHELL_COMMAND_RECORD_PROVIDER_STATES: {
-                return runRecordProviderStates();
+            case SHELL_COMMAND_CLEAR_RECORDED_PROVIDER_STATES: {
+                return runClearRecordedProviderStates();
             }
             case SHELL_COMMAND_DUMP_STATE: {
                 return runDumpControllerState();
@@ -105,47 +105,33 @@
         pw.printf("    Print this help text.\n");
         pw.printf("  %s\n", SHELL_COMMAND_START);
         pw.printf("    Starts the service, creating location time zone providers.\n");
+        pw.printf("  %s <primary package name|%2$s> <secondary package name|%2$s>"
+                        + " <record states>\n",
+                SHELL_COMMAND_START_WITH_TEST_PROVIDERS, NULL_PACKAGE_NAME_TOKEN);
+        pw.printf("    Starts the service with test provider packages configured / provider"
+                + " permission checks disabled.\n");
+        pw.printf("    <record states> - true|false, determines whether state recording is enabled."
+                + "\n");
+        pw.printf("    See %s and %s.\n", SHELL_COMMAND_DUMP_STATE,
+                SHELL_COMMAND_CLEAR_RECORDED_PROVIDER_STATES);
         pw.printf("  %s\n", SHELL_COMMAND_STOP);
         pw.printf("    Stops the service, destroying location time zone providers.\n");
-        pw.printf("  %s (true|false)\n", SHELL_COMMAND_RECORD_PROVIDER_STATES);
-        pw.printf("    Enables / disables provider state recording mode. See also %s. The default"
-                + " state is always \"false\".\n", SHELL_COMMAND_DUMP_STATE);
-        pw.printf("    Note: When enabled, this mode consumes memory and it is only intended for"
-                + " testing.\n");
-        pw.printf("    It should be disabled after use, or the device can be rebooted to"
-                + " reset the mode to disabled.\n");
-        pw.printf("    Disabling (or enabling repeatedly) clears any existing stored states.\n");
+        pw.printf("  %s\n", SHELL_COMMAND_CLEAR_RECORDED_PROVIDER_STATES);
+        pw.printf("    Clears recorded provider state. See also %s and %s.\n",
+                SHELL_COMMAND_START_WITH_TEST_PROVIDERS, SHELL_COMMAND_DUMP_STATE);
+        pw.printf("    Note: This is only intended for use during testing.\n");
         pw.printf("  %s [%s]\n", SHELL_COMMAND_DUMP_STATE, DUMP_STATE_OPTION_PROTO);
         pw.printf("    Dumps service state for tests as text or binary proto form.\n");
         pw.printf("    See the LocationTimeZoneManagerServiceStateProto definition for details.\n");
-        pw.printf("  %s <provider index> <test command>\n",
-                SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
-        pw.printf("    Passes a test command to the named provider.\n");
-        pw.println();
-        pw.printf("<provider index> = 0 (primary), 1 (secondary)\n");
-        pw.println();
-        pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
-        pw.println();
-        pw.printf("Provider <test command> encoding:\n");
-        pw.println();
-        TestCommand.printShellCommandEncodingHelp(pw);
-        pw.println();
-        pw.printf("Simulated provider mode can be used to test the system server behavior or to"
-                + " reproduce bugs without the complexity of using real providers.\n");
-        pw.println();
-        pw.printf("The test commands for simulated providers are:\n");
-        SimulatedLocationTimeZoneProviderProxy.printTestCommandShellHelp(pw);
-        pw.println();
-        pw.printf("Test commands cannot currently be passed to real provider implementations.\n");
         pw.println();
         pw.printf("This service is also affected by the following device_config flags in the"
                 + " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
         pw.printf("  %s\n", KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE);
-        pw.printf("    Overrides the mode of the primary provider. Values=%s|%s|%s\n",
-                PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+        pw.printf("    Overrides the mode of the primary provider. Values=%s|%s\n",
+                PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED);
         pw.printf("  %s\n", KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE);
-        pw.printf("    Overrides the mode of the secondary provider. Values=%s|%s|%s\n",
-                PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED);
+        pw.printf("    Overrides the mode of the secondary provider. Values=%s|%s\n",
+                PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED);
         pw.printf("  %s\n", KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS);
         pw.printf("    Sets the amount of time the service waits when uncertain before making an"
                 + " 'uncertain' suggestion to the time zone detector.\n");
@@ -178,6 +164,23 @@
         return 0;
     }
 
+    private int runStartWithTestProviders() {
+        String testPrimaryProviderPackageName = parseProviderPackageName(getNextArgRequired());
+        String testSecondaryProviderPackageName = parseProviderPackageName(getNextArgRequired());
+        boolean recordProviderStateChanges = Boolean.parseBoolean(getNextArgRequired());
+
+        try {
+            mService.startWithTestProviders(testPrimaryProviderPackageName,
+                    testSecondaryProviderPackageName, recordProviderStateChanges);
+        } catch (RuntimeException e) {
+            reportError(e);
+            return 1;
+        }
+        PrintWriter outPrintWriter = getOutPrintWriter();
+        outPrintWriter.println("Service started (test mode)");
+        return 0;
+    }
+
     private int runStop() {
         try {
             mService.stop();
@@ -190,20 +193,9 @@
         return 0;
     }
 
-    private int runRecordProviderStates() {
-        PrintWriter outPrintWriter = getOutPrintWriter();
-        boolean enabled;
+    private int runClearRecordedProviderStates() {
         try {
-            String nextArg = getNextArgRequired();
-            enabled = Boolean.parseBoolean(nextArg);
-        } catch (RuntimeException e) {
-            reportError(e);
-            return 1;
-        }
-
-        outPrintWriter.println("Setting provider state recording to " + enabled);
-        try {
-            mService.setProviderStateRecordingEnabled(enabled);
+            mService.clearRecordedProviderStates();
         } catch (IllegalStateException e) {
             reportError(e);
             return 2;
@@ -293,47 +285,17 @@
         }
     }
 
-    private int runSendProviderTestCommand() {
-        PrintWriter outPrintWriter = getOutPrintWriter();
-
-        int providerIndex;
-        TestCommand testCommand;
-        try {
-            providerIndex = parseProviderIndex(getNextArgRequired());
-            testCommand = createTestCommandFromNextShellArg();
-        } catch (RuntimeException e) {
-            reportError(e);
-            return 1;
-        }
-
-        outPrintWriter.println("Injecting testCommand=" + testCommand
-                + " to providerIndex=" + providerIndex);
-        try {
-            Bundle result = mService.handleProviderTestCommand(providerIndex, testCommand);
-            outPrintWriter.println(result);
-        } catch (RuntimeException e) {
-            reportError(e);
-            return 2;
-        }
-        return 0;
-    }
-
-    @NonNull
-    private TestCommand createTestCommandFromNextShellArg() {
-        return TestCommand.createFromShellCommandArgs(this);
-    }
-
-    private void reportError(Throwable e) {
+    private void reportError(@NonNull Throwable e) {
         PrintWriter errPrintWriter = getErrPrintWriter();
         errPrintWriter.println("Error: ");
         e.printStackTrace(errPrintWriter);
     }
 
-    private static int parseProviderIndex(@NonNull String providerIndexString) {
-        int providerIndex = Integer.parseInt(providerIndexString);
-        if (providerIndex < 0 || providerIndex > 1) {
-            throw new IllegalArgumentException(providerIndexString);
+    @Nullable
+    private static String parseProviderPackageName(@NonNull String providerPackageNameString) {
+        if (providerPackageNameString.equals(NULL_PACKAGE_NAME_TOKEN)) {
+            return null;
         }
-        return providerIndex;
+        return providerPackageNameString;
     }
 }
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index c0fd6b1..4e87833 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -16,9 +16,6 @@
 
 package com.android.server.timezonedetector.location;
 
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
-
 import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.debugLog;
 import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.warnLog;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
@@ -35,9 +32,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.RemoteCallback;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
@@ -358,8 +353,7 @@
     /**
      * Usually {@code false} but can be set to {@code true} for testing.
      */
-    @GuardedBy("mSharedLock")
-    private boolean mStateChangeRecording;
+    private final boolean mRecordStateChanges;
 
     @GuardedBy("mSharedLock")
     @NonNull
@@ -385,7 +379,8 @@
     LocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
             @NonNull ThreadingDomain threadingDomain,
             @NonNull String providerName,
-            @NonNull TimeZoneProviderEventPreProcessor timeZoneProviderEventPreProcessor) {
+            @NonNull TimeZoneProviderEventPreProcessor timeZoneProviderEventPreProcessor,
+            boolean recordStateChanges) {
         mThreadingDomain = Objects.requireNonNull(threadingDomain);
         mProviderMetricsLogger = Objects.requireNonNull(providerMetricsLogger);
         mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue();
@@ -393,6 +388,7 @@
         mProviderName = Objects.requireNonNull(providerName);
         mTimeZoneProviderEventPreProcessor =
                 Objects.requireNonNull(timeZoneProviderEventPreProcessor);
+        mRecordStateChanges = recordStateChanges;
     }
 
     /**
@@ -456,12 +452,11 @@
     abstract void onDestroy();
 
     /**
-     * Sets the provider into state recording mode for tests.
+     * Clears recorded state changes.
      */
-    final void setStateChangeRecordingEnabled(boolean enabled) {
+    final void clearRecordedStates() {
         mThreadingDomain.assertCurrentThread();
         synchronized (mSharedLock) {
-            mStateChangeRecording = enabled;
             mRecordedStates.clear();
             mRecordedStates.trimToSize();
         }
@@ -478,12 +473,11 @@
     }
 
     /**
-     * Set the current state, for use by this class and subclasses only. If {@code #notifyChanges}
-     * is {@code true} and {@code newState} is not equal to the old state, then {@link
-     * ProviderListener#onProviderStateChange(ProviderState)} must be called on
-     * {@link #mProviderListener}.
+     * Sets the current state. If {@code #notifyChanges} is {@code true} and {@code newState} is not
+     * equal to the old state, then {@link ProviderListener#onProviderStateChange(ProviderState)}
+     * will be called on {@link #mProviderListener}.
      */
-    final void setCurrentState(@NonNull ProviderState newState, boolean notifyChanges) {
+    private void setCurrentState(@NonNull ProviderState newState, boolean notifyChanges) {
         mThreadingDomain.assertCurrentThread();
         synchronized (mSharedLock) {
             ProviderState oldState = mCurrentState.get();
@@ -491,7 +485,7 @@
             onSetCurrentState(newState);
             if (!Objects.equals(newState, oldState)) {
                 mProviderMetricsLogger.onProviderStateChanged(newState.stateEnum);
-                if (mStateChangeRecording) {
+                if (mRecordStateChanges) {
                     mRecordedStates.add(newState);
                 }
                 if (notifyChanges) {
@@ -609,23 +603,6 @@
      */
     abstract void onStopUpdates();
 
-    /**
-     * Overridden by subclasses to handle the supplied {@link TestCommand}. If {@code callback} is
-     * non-null, the default implementation sends a result {@link Bundle} with {@link
-     * android.service.timezone.TimeZoneProviderService#TEST_COMMAND_RESULT_SUCCESS_KEY} set to
-     * {@code false} and a "Not implemented" error message.
-     */
-    void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
-        Objects.requireNonNull(testCommand);
-
-        if (callback != null) {
-            Bundle result = new Bundle();
-            result.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, false);
-            result.putString(TEST_COMMAND_RESULT_ERROR_KEY, "Not implemented");
-            callback.sendResult(result);
-        }
-    }
-
     /** For subclasses to invoke when a {@link TimeZoneProviderEvent} has been received. */
     final void handleTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
         mThreadingDomain.assertCurrentThread();
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderProxy.java
index 43b1b5f0..7b1a77c 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProviderProxy.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Handler;
-import android.os.RemoteCallback;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
@@ -113,13 +112,6 @@
     abstract void setRequest(@NonNull TimeZoneProviderRequest request);
 
     /**
-     * Processes the supplied test command. An optional callback can be supplied to listen for a
-     * response.
-     */
-    abstract void handleTestCommand(@NonNull TestCommand testCommand,
-            @Nullable RemoteCallback callback);
-
-    /**
      * Handles a {@link TimeZoneProviderEvent} from a remote process.
      */
     final void handleTimeZoneProviderEvent(@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/NullLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/NullLocationTimeZoneProviderProxy.java
index 1f45e82..4ef819f 100644
--- a/services/core/java/com/android/server/timezonedetector/location/NullLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/NullLocationTimeZoneProviderProxy.java
@@ -19,9 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteCallback;
-import android.service.timezone.TimeZoneProviderService;
 import android.util.IndentingPrintWriter;
 
 /**
@@ -67,17 +64,6 @@
     }
 
     @Override
-    void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
-        if (callback != null) {
-            Bundle result = new Bundle();
-            result.putBoolean(TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY, false);
-            result.putString(TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY,
-                    "Provider is disabled");
-            callback.sendResult(result);
-        }
-    }
-
-    @Override
     public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
         synchronized (mSharedLock) {
             ipw.println("{NullLocationTimeZoneProviderProxy}");
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
index b5ac712..fcac3e8 100644
--- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java
@@ -18,16 +18,12 @@
 
 import static android.Manifest.permission.BIND_TIME_ZONE_PROVIDER_SERVICE;
 import static android.Manifest.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.RemoteCallback;
 import android.service.timezone.ITimeZoneProvider;
 import android.service.timezone.ITimeZoneProviderManager;
 import android.service.timezone.TimeZoneProviderSuggestion;
@@ -62,19 +58,27 @@
     RealLocationTimeZoneProviderProxy(
             @NonNull Context context, @NonNull Handler handler,
             @NonNull ThreadingDomain threadingDomain, @NonNull String action,
-            @NonNull String providerPackageName) {
+            @NonNull String providerPackageName, boolean isTestProvider) {
         super(context, threadingDomain);
         mManagerProxy = null;
         mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
 
         Objects.requireNonNull(providerPackageName);
-        mServiceWatcher = ServiceWatcher.create(context,
-                handler,
-                "RealLocationTimeZoneProviderProxy",
-                new CurrentUserServiceSupplier(context, action,
-                        providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE,
-                        INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE),
-                this);
+
+        CurrentUserServiceSupplier serviceSupplier;
+        if (isTestProvider) {
+            // For tests it is possible to bypass the provider service permission checks, since
+            // the tests are expected to install fake providers.
+            serviceSupplier = CurrentUserServiceSupplier.createUnsafeForTestsOnly(
+                    context, action, providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE,
+                    /*servicePermission=*/null);
+        } else {
+            serviceSupplier = CurrentUserServiceSupplier.create(context, action,
+                    providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE,
+                    INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE);
+        }
+        mServiceWatcher = ServiceWatcher.create(
+                context, handler, "RealLocationTimeZoneProviderProxy", serviceSupplier, this);
     }
 
     @Override
@@ -155,21 +159,6 @@
         });
     }
 
-    /**
-     * A stubbed implementation.
-     */
-    @Override
-    void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
-        mThreadingDomain.assertCurrentThread();
-
-        if (callback != null) {
-            Bundle result = new Bundle();
-            result.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, false);
-            result.putString(TEST_COMMAND_RESULT_ERROR_KEY, "Not implemented");
-            callback.sendResult(result);
-        }
-    }
-
     @Override
     public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
         synchronized (mSharedLock) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/SimulatedLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/SimulatedLocationTimeZoneProviderProxy.java
deleted file mode 100644
index 02b0a84..0000000
--- a/services/core/java/com/android/server/timezonedetector/location/SimulatedLocationTimeZoneProviderProxy.java
+++ /dev/null
@@ -1,211 +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.timezonedetector.location;
-
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_ON_BIND;
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_ON_UNBIND;
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_PERM_FAILURE;
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS;
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS_ARG_KEY_TZ;
-import static android.app.time.LocationTimeZoneManager.SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteCallback;
-import android.os.SystemClock;
-import android.service.timezone.TimeZoneProviderSuggestion;
-import android.util.IndentingPrintWriter;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.timezonedetector.ReferenceWithHistory;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * A replacement for a real binder proxy for use during integration testing
- * that can be used to inject simulated {@link LocationTimeZoneProviderProxy} behavior.
- */
-class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
-
-    @GuardedBy("mSharedLock")
-    @NonNull private TimeZoneProviderRequest mRequest;
-
-    @GuardedBy("mSharedLock")
-    @NonNull private final ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
-
-    SimulatedLocationTimeZoneProviderProxy(
-            @NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
-        super(context, threadingDomain);
-        mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
-    }
-
-    @Override
-    void onInitialize() {
-        // No-op - nothing to do for the simulated provider.
-    }
-
-    @Override
-    void onDestroy() {
-        // No-op - nothing to do for the simulated provider.
-    }
-
-    void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
-        mThreadingDomain.assertCurrentThread();
-
-        Objects.requireNonNull(testCommand);
-
-        synchronized (mSharedLock) {
-            Bundle resultBundle = new Bundle();
-            switch (testCommand.getName()) {
-                case SIMULATED_PROVIDER_TEST_COMMAND_ON_BIND: {
-                    mLastEvent.set("Simulating onProviderBound(), testCommand=" + testCommand);
-                    mThreadingDomain.post(this::onBindOnHandlerThread);
-                    resultBundle.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, true);
-                    break;
-                }
-                case SIMULATED_PROVIDER_TEST_COMMAND_ON_UNBIND: {
-                    mLastEvent.set("Simulating onProviderUnbound(), testCommand=" + testCommand);
-                    mThreadingDomain.post(this::onUnbindOnHandlerThread);
-                    resultBundle.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, true);
-                    break;
-                }
-                case SIMULATED_PROVIDER_TEST_COMMAND_PERM_FAILURE:
-                case SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN:
-                case SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS: {
-                    if (!mRequest.sendUpdates()) {
-                        String errorMsg = "testCommand=" + testCommand
-                                + " is testing an invalid case:"
-                                + " updates are off. mRequest=" + mRequest;
-                        mLastEvent.set(errorMsg);
-                        resultBundle.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, false);
-                        resultBundle.putString(TEST_COMMAND_RESULT_ERROR_KEY, errorMsg);
-                        break;
-                    }
-                    mLastEvent.set("Simulating TimeZoneProviderEvent, testCommand=" + testCommand);
-                    TimeZoneProviderEvent timeZoneProviderEvent =
-                            createTimeZoneProviderEventFromTestCommand(testCommand);
-                    handleTimeZoneProviderEvent(timeZoneProviderEvent);
-                    resultBundle.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, true);
-                    break;
-                }
-                default: {
-                    String errorMsg = "Unknown test event type. testCommand=" + testCommand;
-                    mLastEvent.set(errorMsg);
-                    resultBundle.putBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY, false);
-                    resultBundle.putString(TEST_COMMAND_RESULT_ERROR_KEY, errorMsg);
-                    break;
-                }
-            }
-            if (callback != null) {
-                callback.sendResult(resultBundle);
-            }
-        }
-    }
-
-    private void onBindOnHandlerThread() {
-        mThreadingDomain.assertCurrentThread();
-
-        synchronized (mSharedLock) {
-            mListener.onProviderBound();
-        }
-    }
-
-    private void onUnbindOnHandlerThread() {
-        mThreadingDomain.assertCurrentThread();
-
-        synchronized (mSharedLock) {
-            mListener.onProviderUnbound();
-        }
-    }
-
-    @Override
-    final void setRequest(@NonNull TimeZoneProviderRequest request) {
-        mThreadingDomain.assertCurrentThread();
-
-        Objects.requireNonNull(request);
-        synchronized (mSharedLock) {
-            mLastEvent.set("Request received: " + request);
-            mRequest = request;
-        }
-    }
-
-    @Override
-    public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
-        synchronized (mSharedLock) {
-            ipw.println("{SimulatedLocationTimeZoneProviderProxy}");
-            ipw.println("mRequest=" + mRequest);
-            ipw.println("mLastEvent=" + mLastEvent);
-
-            ipw.increaseIndent();
-            ipw.println("Last event history:");
-            mLastEvent.dump(ipw);
-            ipw.decreaseIndent();
-        }
-    }
-
-    /**
-     * Prints the command line options that to create a {@link TestCommand} that can be passed to
-     * {@link #createTimeZoneProviderEventFromTestCommand(TestCommand)}.
-     */
-    static void printTestCommandShellHelp(@NonNull PrintWriter pw) {
-        pw.printf("%s\n", SIMULATED_PROVIDER_TEST_COMMAND_ON_BIND);
-        pw.printf("%s\n", SIMULATED_PROVIDER_TEST_COMMAND_ON_UNBIND);
-        pw.printf("%s\n", SIMULATED_PROVIDER_TEST_COMMAND_PERM_FAILURE);
-        pw.printf("%s\n", SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN);
-        pw.printf("%s %s=string_array:<time zone id>[&<time zone id>]+\n",
-                SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS,
-                SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS_ARG_KEY_TZ);
-    }
-
-    @NonNull
-    private static TimeZoneProviderEvent createTimeZoneProviderEventFromTestCommand(
-            @NonNull TestCommand testCommand) {
-        String name = testCommand.getName();
-        switch (name) {
-            case SIMULATED_PROVIDER_TEST_COMMAND_PERM_FAILURE: {
-                return TimeZoneProviderEvent.createPermanentFailureEvent("Simulated failure");
-            }
-            case SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN: {
-                return TimeZoneProviderEvent.createUncertainEvent();
-            }
-            case SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS: {
-                Bundle args = testCommand.getArgs();
-                String[] timeZoneIds = args.getStringArray(
-                        SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS_ARG_KEY_TZ);
-                if (timeZoneIds == null) {
-                    throw new IllegalArgumentException("No "
-                            + SIMULATED_PROVIDER_TEST_COMMAND_SUCCESS_ARG_KEY_TZ + " arg found");
-                }
-                TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
-                        .setTimeZoneIds(Arrays.asList(timeZoneIds))
-                        .setElapsedRealtimeMillis(SystemClock.elapsedRealtime())
-                        .build();
-                return TimeZoneProviderEvent.createSuggestionEvent(suggestion);
-            }
-            default: {
-                String msg = String.format("Error: Unknown command name %s", name);
-                throw new IllegalArgumentException(msg);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/timezonedetector/location/TestCommand.java b/services/core/java/com/android/server/timezonedetector/location/TestCommand.java
deleted file mode 100644
index 21482ea..0000000
--- a/services/core/java/com/android/server/timezonedetector/location/TestCommand.java
+++ /dev/null
@@ -1,194 +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.timezonedetector.location;
-
-import android.annotation.NonNull;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ShellCommand;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A command used to trigger behaviors in a component during tests. Routing to the correct
- * component is not handled by this class. The meaning of the {@code name} and {@code args}
- * properties are component-specific.
- *
- * <p>{@link TestCommand}s can be encoded as arguments in a shell command. See
- * {@link #createFromShellCommandArgs(ShellCommand)} and {@link
- * #printShellCommandEncodingHelp(PrintWriter)}.
- */
-final class TestCommand {
-
-    private static final Pattern SHELL_ARG_PATTERN = Pattern.compile("([^=]+)=([^:]+):(.*)");
-    private static final Pattern SHELL_ARG_VALUE_SPLIT_PATTERN = Pattern.compile("&");
-
-    @NonNull private final String mName;
-    @NonNull private final Bundle mArgs;
-
-    /** Creates a {@link TestCommand} from components. */
-    private TestCommand(@NonNull String type, @NonNull Bundle args) {
-        mName = Objects.requireNonNull(type);
-        mArgs = Objects.requireNonNull(args);
-    }
-
-    @VisibleForTesting
-    @NonNull
-    public static TestCommand createForTests(@NonNull String type, @NonNull Bundle args) {
-        return new TestCommand(type, args);
-    }
-
-    /**
-     * Creates a {@link TestCommand} from a {@link ShellCommand}'s remaining arguments.
-     *
-     * See {@link #printShellCommandEncodingHelp(PrintWriter)} for encoding details.
-     */
-    @NonNull
-    public static TestCommand createFromShellCommandArgs(@NonNull ShellCommand shellCommand) {
-        String name = shellCommand.getNextArgRequired();
-        Bundle args = new Bundle();
-        String argKeyAndValue;
-        while ((argKeyAndValue = shellCommand.getNextArg()) != null) {
-            Matcher matcher = SHELL_ARG_PATTERN.matcher(argKeyAndValue);
-            if (!matcher.matches()) {
-                throw new IllegalArgumentException(
-                        argKeyAndValue + " does not match " + SHELL_ARG_PATTERN);
-            }
-            String key = matcher.group(1);
-            String type = matcher.group(2);
-            String encodedValue = matcher.group(3);
-            Object value = getTypedValue(type, encodedValue);
-            args.putObject(key, value);
-        }
-        return new TestCommand(name, args);
-    }
-
-    /**
-     * Returns the command's name.
-     */
-    @NonNull
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * Returns the arg values. Returns an empty bundle if there are no args.
-     */
-    @NonNull
-    public Bundle getArgs() {
-        return mArgs.deepCopy();
-    }
-
-    @Override
-    public String toString() {
-        return "TestCommand{"
-                + "mName=" + mName
-                + ", mArgs=" + mArgs
-                + '}';
-    }
-
-    /**
-     * Prints the text format that {@link #createFromShellCommandArgs(ShellCommand)} understands.
-     */
-    public static void printShellCommandEncodingHelp(@NonNull PrintWriter pw) {
-        pw.println("Test commands are encoded on the command line as: <name> <arg>*");
-        pw.println();
-        pw.println("The <name> is a string");
-        pw.println("The <arg> encoding is: \"key=type:value\"");
-        pw.println();
-        pw.println("e.g. \"myKey=string:myValue\" represents an argument with the key \"myKey\""
-                + " and a string value of \"myValue\"");
-        pw.println("Values are one or more URI-encoded strings separated by & characters. Only some"
-                + " types support multiple values, e.g. string arrays.");
-        pw.println();
-        pw.println("Recognized types are: string, boolean, double, long, string_array.");
-        pw.println();
-        pw.println("When passing test commands via adb shell, the & can be escaped by quoting the"
-                + " <arg> and escaping the & with \\");
-        pw.println("For example:");
-        pw.println("  $ adb shell ... my-command \"key1=string_array:value1\\&value2\"");
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        TestCommand that = (TestCommand) o;
-        return mName.equals(that.mName)
-                && mArgs.kindofEquals(that.mArgs);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mName, mArgs);
-    }
-
-
-    private static Object getTypedValue(String type, String encodedValue) {
-        // The value is stored in a URL encoding. Multiple value types have values separated with
-        // a & character.
-        String[] values = SHELL_ARG_VALUE_SPLIT_PATTERN.split(encodedValue);
-
-        // URI decode the values.
-        for (int i = 0; i < values.length; i++) {
-            values[i] = Uri.decode(values[i]);
-        }
-
-        switch (type) {
-            case "boolean": {
-                checkSingleValue(values);
-                return Boolean.parseBoolean(values[0]);
-            }
-            case "double": {
-                checkSingleValue(values);
-                return Double.parseDouble(values[0]);
-            }
-            case "long": {
-                checkSingleValue(values);
-                return Long.parseLong(values[0]);
-            }
-            case "string": {
-                checkSingleValue(values);
-                return values[0];
-            }
-            case "string_array": {
-                return values;
-            }
-            default: {
-                throw new IllegalArgumentException("Unknown type: " + type);
-            }
-        }
-
-    }
-
-    private static void checkSingleValue(String[] values) {
-        if (values.length != 1) {
-            throw new IllegalArgumentException("Expected a single value, but there were multiple: "
-                    + Arrays.toString(values));
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 0c04b07..22f0ada 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.media.IResourceManagerService;
 import android.media.tv.TvInputManager;
-import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
 import android.media.tv.tunerresourcemanager.ITunerResourceManager;
@@ -31,6 +30,7 @@
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
+import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e85fa23..0f4f58b 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -228,17 +228,20 @@
 
             Vibration.Status status = null;
             while (!mStepQueue.isEmpty()) {
-                long waitTime = mStepQueue.calculateWaitTime();
-                if (waitTime <= 0) {
-                    mStepQueue.consumeNext();
-                } else {
-                    synchronized (mLock) {
+                long waitTime;
+                synchronized (mLock) {
+                    waitTime = mStepQueue.calculateWaitTime();
+                    if (waitTime > 0) {
                         try {
                             mLock.wait(waitTime);
                         } catch (InterruptedException e) {
                         }
                     }
                 }
+                // If we waited, the queue may have changed, so let the loop run again.
+                if (waitTime <= 0) {
+                    mStepQueue.consumeNext();
+                }
                 Vibration.Status currentStatus = mStop ? Vibration.Status.CANCELLED
                         : mStepQueue.calculateVibrationStatus(sequentialEffectSize);
                 if (status == null && currentStatus != Vibration.Status.RUNNING) {
@@ -387,15 +390,13 @@
         }
 
         /** Returns the time in millis to wait before calling {@link #consumeNext()}. */
+        @GuardedBy("mLock")
         public long calculateWaitTime() {
-            Step nextStep;
-            synchronized (mLock) {
-                if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
-                    // Steps anticipated by vibrator complete callback should be played right away.
-                    return 0;
-                }
-                nextStep = mNextSteps.peek();
+            if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
+                // Steps anticipated by vibrator complete callback should be played right away.
+                return 0;
             }
+            Step nextStep = mNextSteps.peek();
             return nextStep == null ? 0 : nextStep.calculateWaitTime();
         }
 
@@ -603,7 +604,10 @@
             return false;
         }
 
-        /** Returns the time in millis to wait before playing this step. */
+        /**
+         * Returns the time in millis to wait before playing this step. This is performed
+         * while holding the queue lock, so should not rely on potentially slow operations.
+         */
         public long calculateWaitTime() {
             if (startTime == Long.MAX_VALUE) {
                 // This step don't have a predefined start time, it's just marked to be executed
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fe4eead..372d3ec 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -43,6 +43,7 @@
 import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowTracing.WINSCOPE_EXT;
 import static com.android.server.wm.utils.RegionUtils.forEachRect;
 
 import android.accessibilityservice.AccessibilityTrace;
@@ -1959,7 +1960,8 @@
         }
 
         private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
-        private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace.pb";
+        private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace"
+                + WINSCOPE_EXT;
         private static final String TAG = "AccessibilityTracing";
         private static final long MAGIC_NUMBER_VALUE =
                 ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 331b8de..675c7eb 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1197,10 +1197,10 @@
 
                 final Task task = r.getTask();
                 isLastRunningActivity = task.topRunningActivity() == r;
-                final Intent baseIntent = task.getBaseIntent();
-                final boolean activityIsBaseActivity = baseIntent != null
-                        && r.mActivityComponent.equals(baseIntent.getComponent());
-                baseActivityIntent = activityIsBaseActivity ? r.intent : null;
+
+                final boolean isBaseActivity = r.mActivityComponent.equals(task.realActivity);
+                baseActivityIntent = isBaseActivity ? r.intent : null;
+
                 launchedFromHome = r.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME);
             }
 
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 005a62a..20958aa 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -633,6 +633,7 @@
             if (crossPackage) {
                 startLaunchTrace(info);
             }
+            scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
             return;
         }
 
@@ -654,13 +655,7 @@
             // As abort for no process switch.
             launchObserverNotifyIntentFailed();
         }
-        if (launchedActivity.mDisplayContent.isSleeping()) {
-            // It is unknown whether the activity can be drawn or not, e.g. it depends on the
-            // keyguard states and the attributes or flags set by the activity. If the activity
-            // keeps invisible in the grace period, the tracker will be cancelled so it won't get
-            // a very long launch time that takes unlocking as the end of launch.
-            scheduleCheckActivityToBeDrawn(launchedActivity, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
-        }
+        scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
 
         // If the previous transitions are no longer visible, abort them to avoid counting the
         // launch time when resuming from back stack. E.g. launch 2 independent tasks in a short
@@ -675,6 +670,16 @@
         }
     }
 
+    private void scheduleCheckActivityToBeDrawnIfSleeping(@NonNull ActivityRecord r) {
+        if (r.mDisplayContent.isSleeping()) {
+            // It is unknown whether the activity can be drawn or not, e.g. it depends on the
+            // keyguard states and the attributes or flags set by the activity. If the activity
+            // keeps invisible in the grace period, the tracker will be cancelled so it won't get
+            // a very long launch time that takes unlocking as the end of launch.
+            scheduleCheckActivityToBeDrawn(r, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
+        }
+    }
+
     /**
      * Notifies the tracker that all windows of the app have been drawn.
      *
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6e492d1..87b7660 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -330,8 +330,6 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
-import com.android.internal.util.function.pooled.PooledFunction;
-import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.am.AppTimeTracker;
 import com.android.server.am.PendingIntentRecord;
@@ -704,8 +702,6 @@
     private boolean mInSizeCompatModeForBounds = false;
 
     // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
-    // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
-    // but that isn't reflected in this boolean.
     private boolean mIsAspectRatioApplied = false;
 
     // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -746,6 +742,13 @@
     boolean startingDisplayed;
     boolean startingMoved;
 
+    /**
+     * If it is non-null, it requires all activities who have the same starting data to be drawn
+     * to remove the starting window.
+     * TODO(b/189385912): Remove starting window related fields after migrating them to task.
+     */
+    private StartingData mSharedStartingData;
+
     boolean mHandleExitSplashScreen;
     @TransferSplashScreenState
     int mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
@@ -1085,6 +1088,9 @@
             pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
             pw.print(" mIsExiting="); pw.println(mIsExiting);
         }
+        if (mSharedStartingData != null) {
+            pw.println(prefix + "mSharedStartingData=" + mSharedStartingData);
+        }
         if (mStartingWindow != null || mStartingSurface != null
                 || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
             pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow);
@@ -1173,7 +1179,7 @@
             header.run();
         }
 
-        String innerPrefix = prefix + "      ";
+        String innerPrefix = prefix + "  ";
         String[] args = new String[0];
         if (lastTask != r.getTask()) {
             lastTask = r.getTask();
@@ -1379,9 +1385,11 @@
     }
 
     @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final Task oldTask = oldParent != null ? ((TaskFragment) oldParent).getTask() : null;
-        final Task newTask = newParent != null ? ((TaskFragment) newParent).getTask() : null;
+    void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
+        final TaskFragment oldParent = (TaskFragment) rawOldParent;
+        final TaskFragment newParent = (TaskFragment) rawNewParent;
+        final Task oldTask = oldParent != null ? oldParent.getTask() : null;
+        final Task newTask = newParent != null ? newParent.getTask() : null;
         this.task = newTask;
 
         super.onParentChanged(newParent, oldParent);
@@ -1440,11 +1448,18 @@
         updateColorTransform();
 
         if (oldParent != null) {
-            ((TaskFragment) oldParent).cleanUpActivityReferences(this);
+            oldParent.cleanUpActivityReferences(this);
         }
 
         if (newParent != null && isState(RESUMED)) {
-            ((TaskFragment) newParent).setResumedActivity(this, "onParentChanged");
+            newParent.setResumedActivity(this, "onParentChanged");
+            if (mStartingWindow != null && mStartingData != null
+                    && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) {
+                // The starting window should keep covering its task when the activity is
+                // reparented to a task fragment that may not fill the task bounds.
+                associateStartingDataWithTask();
+                overrideConfigurationPropagation(mStartingWindow, task);
+            }
         }
 
         if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2005,7 +2020,7 @@
     @VisibleForTesting
     boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo,
             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
-            IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
+            ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning,
             boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty) {
         // If the display is frozen, we won't do anything until the actual window is
         // displayed so there is no reason to put in the starting window.
@@ -2064,7 +2079,7 @@
         }
         applyStartingWindowTheme(pkg, resolvedTheme);
 
-        if (transferStartingWindow(transferFrom)) {
+        if (from != null && transferStartingWindow(from)) {
             return true;
         }
 
@@ -2089,6 +2104,11 @@
 
         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
         mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
+        if (task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
+            // Associate with the task so if this activity is resized by task fragment later, the
+            // starting window can keep the same bounds as the task.
+            associateStartingDataWithTask();
+        }
         scheduleAddStartingWindow();
         return true;
     }
@@ -2337,6 +2357,23 @@
         }
     }
 
+    void attachStartingWindow(@NonNull WindowState startingWindow) {
+        mStartingWindow = startingWindow;
+        if (mStartingData != null && mStartingData.mAssociatedTask != null) {
+            // Associate the configuration of starting window with the task.
+            overrideConfigurationPropagation(startingWindow, mStartingData.mAssociatedTask);
+        }
+    }
+
+    private void associateStartingDataWithTask() {
+        mStartingData.mAssociatedTask = task;
+        task.forAllActivities(r -> {
+            if (r.mVisibleRequested && !r.firstWindowDrawn) {
+                r.mSharedStartingData = mStartingData;
+            }
+        });
+    }
+
     void removeStartingWindow() {
         if (transferSplashScreenIfNeeded()) {
             return;
@@ -2346,6 +2383,11 @@
 
     void removeStartingWindowAnimation(boolean prepareAnimation) {
         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
+        if (mSharedStartingData != null) {
+            mSharedStartingData.mAssociatedTask.forAllActivities(r -> {
+                r.mSharedStartingData = null;
+            });
+        }
         if (mStartingWindow == null) {
             if (mStartingData != null) {
                 // Starting window has not been added yet, but it is scheduled to be added.
@@ -2402,20 +2444,6 @@
         }
     }
 
-    private void removeAppTokenFromDisplay() {
-        if (mWmService.mRoot == null) return;
-
-        final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId());
-        if (dc == null) {
-            Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: "
-                    + appToken + " from non-existing displayId=" + getDisplayId());
-            return;
-        }
-        // Resume key dispatching if it is currently paused before we remove the container.
-        resumeKeyDispatchingLocked();
-        dc.removeAppToken(appToken.asBinder());
-    }
-
     /**
      * Reparents this activity into {@param newTaskFrag} at the provided {@param position}. The
      * caller should ensure that the {@param newTaskFrag} is not already the parent of this
@@ -2826,7 +2854,7 @@
     /**
      * @return Whether AppOps allows this package to enter picture-in-picture.
      */
-    private boolean checkEnterPictureInPictureAppOpsState() {
+    boolean checkEnterPictureInPictureAppOpsState() {
         return mAtmService.getAppOpsManager().checkOpNoThrow(
                 OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
     }
@@ -2966,7 +2994,7 @@
     @interface FinishRequest {}
 
     /**
-     * See {@link #finishIfPossible(int, Intent, String, boolean)}
+     * See {@link #finishIfPossible(int, Intent, NeededUriGrants, String, boolean)}
      */
     @FinishRequest int finishIfPossible(String reason, boolean oomAdj) {
         return finishIfPossible(Activity.RESULT_CANCELED,
@@ -3428,7 +3456,9 @@
         setState(DESTROYED, "removeFromHistory");
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
         detachFromProcess();
-        removeAppTokenFromDisplay();
+        // Resume key dispatching if it is currently paused before we remove the container.
+        resumeKeyDispatchingLocked();
+        mDisplayContent.removeAppToken(appToken);
 
         cleanUpActivityServices();
         removeUriPermissionsLocked();
@@ -3453,7 +3483,13 @@
         if (stopped) {
             abortAndClearOptionsAnimation();
         }
-        mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+        if (mAtmService.getTransitionController().isCollecting()) {
+            // We don't want the finishing to change the transition ready state since there will not
+            // be corresponding setReady for finishing.
+            mAtmService.getTransitionController().collectExistenceChange(this);
+        } else {
+            mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+        }
     }
 
     /**
@@ -3639,12 +3675,17 @@
 
     @Override
     void removeImmediately() {
-        if (!finishing) {
+        if (mState != DESTROYED) {
+            Slog.w(TAG, "Force remove immediately " + this + " state=" + mState);
             // If Task#removeImmediately is called directly with alive activities, ensure that the
             // activities are destroyed and detached from process.
             destroyImmediately("removeImmediately");
+            // Complete the destruction immediately because this activity will not be found in
+            // hierarchy, it is unable to report completion.
+            destroyed("removeImmediately");
+        } else {
+            onRemovedFromDisplay();
         }
-        onRemovedFromDisplay();
         super.removeImmediately();
     }
 
@@ -3858,12 +3899,7 @@
         }
     }
 
-    boolean transferStartingWindow(IBinder transferFrom) {
-        final ActivityRecord fromActivity = getDisplayContent().getActivityRecord(transferFrom);
-        if (fromActivity == null) {
-            return false;
-        }
-
+    private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
         final WindowState tStartingWindow = fromActivity.mStartingWindow;
         if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
             // In this case, the starting icon has already been displayed, so start
@@ -3884,6 +3920,7 @@
 
                 // Transfer the starting window over to the new token.
                 mStartingData = fromActivity.mStartingData;
+                mSharedStartingData = fromActivity.mSharedStartingData;
                 mStartingSurface = fromActivity.mStartingSurface;
                 startingDisplayed = fromActivity.startingDisplayed;
                 fromActivity.startingDisplayed = false;
@@ -3946,6 +3983,7 @@
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
                     "Moving pending starting from %s to %s", fromActivity, this);
             mStartingData = fromActivity.mStartingData;
+            mSharedStartingData = fromActivity.mSharedStartingData;
             fromActivity.mStartingData = null;
             fromActivity.startingMoved = true;
             scheduleAddStartingWindow();
@@ -3964,16 +4002,10 @@
      * immediately finishes after, so we have to transfer T to M.
      */
     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
-        final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow,
-                this, PooledLambda.__(ActivityRecord.class));
-        task.forAllActivities(p);
-        p.recycle();
-    }
-
-    private boolean transferStartingWindow(ActivityRecord fromActivity) {
-        if (fromActivity == this) return true;
-
-        return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token);
+        task.forAllActivities(fromActivity -> {
+            if (fromActivity == this) return true;
+            return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity);
+        });
     }
 
     void checkKeyguardFlagsChanged() {
@@ -5156,6 +5188,7 @@
     void notifyAppStopped() {
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
         mAppStopped = true;
+        firstWindowDrawn = false;
         // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
         // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
         // Clear any surface transactions and content overlay in this case.
@@ -5919,7 +5952,7 @@
         }
     }
 
-    void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
+    void onFirstWindowDrawn(WindowState win) {
         firstWindowDrawn = true;
         // stop tracking
         mSplashScreenStyleEmpty = true;
@@ -5935,7 +5968,22 @@
             // own stuff.
             win.cancelAnimation();
         }
-        removeStartingWindow();
+
+        // Remove starting window directly if is in a pure task. Otherwise if it is associated with
+        // a task (e.g. nested task fragment), then remove only if all visible windows in the task
+        // are drawn.
+        final Task associatedTask =
+                mSharedStartingData != null ? mSharedStartingData.mAssociatedTask : null;
+        if (associatedTask == null) {
+            removeStartingWindow();
+        } else if (associatedTask.getActivity(
+                r -> r.mVisibleRequested && !r.firstWindowDrawn) == null) {
+            // The last drawn activity may not be the one that owns the starting window.
+            final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
+            if (r != null) {
+                r.removeStartingWindow();
+            }
+        }
         updateReportedVisibilityLocked();
     }
 
@@ -6506,8 +6554,7 @@
 
         final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
                 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
-                prev != null ? prev.appToken : null,
-                newTask || newSingleActivity, taskSwitch, isProcessRunning(),
+                prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(),
                 allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
         if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
             Slog.d(TAG, "Scheduled starting window for " + this);
@@ -6572,17 +6619,6 @@
         }
     }
 
-    boolean hasWindowsAlive() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            // No need to loop through child windows as the answer should be the same as that of the
-            // parent window.
-            if (!(mChildren.get(i)).mAppDied) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     void setWillReplaceWindows(boolean animate) {
         ProtoLog.d(WM_DEBUG_ADD_REMOVE,
                 "Marking app token %s with replacing windows.", this);
@@ -7450,11 +7486,14 @@
      * requested orientation. If not, it may be necessary to letterbox the window.
      * @param parentBounds are the new parent bounds passed down to the activity and should be used
      *                     to compute the stable bounds.
-     * @param outBounds will store the stable bounds, which are the bounds with insets applied.
-     *                  These should be used to compute letterboxed bounds if orientation is not
-     *                  respected when insets are applied.
+     * @param outStableBounds will store the stable bounds, which are the bounds with insets
+     *                        applied, if orientation is not respected when insets are applied.
+     *                        Otherwise outStableBounds will be empty. Stable bounds should be used
+     *                        to compute letterboxed bounds if orientation is not respected when
+     *                        insets are applied.
      */
-    private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outBounds) {
+    private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds) {
+        outStableBounds.setEmpty();
         if (mDisplayContent == null) {
             return true;
         }
@@ -7469,17 +7508,21 @@
         // Compute orientation from stable parent bounds (= parent bounds with insets applied)
         final Task task = getTask();
         task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
-                outBounds /* outStableBounds */, parentBounds /* bounds */,
+                outStableBounds /* outStableBounds */, parentBounds /* bounds */,
                 mDisplayContent.getDisplayInfo());
-        final int orientationWithInsets = outBounds.height() >= outBounds.width()
+        final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
         // If orientation does not match the orientation with insets applied, then a
         // display rotation will not be enough to respect orientation. However, even if they do
         // not match but the orientation with insets applied matches the requested orientation, then
         // there is no need to modify the bounds because when insets are applied, the activity will
         // have the desired orientation.
-        return orientation == orientationWithInsets
+        final boolean orientationRespectedWithInsets = orientation == orientationWithInsets
                 || orientationWithInsets == requestedOrientation;
+        if (orientationRespectedWithInsets) {
+            outStableBounds.setEmpty();
+        }
+        return orientationRespectedWithInsets;
     }
 
     /**
@@ -7497,9 +7540,10 @@
             int windowingMode) {
         mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
         final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
-        final Rect containerBounds = new Rect(parentBounds);
+        final Rect stableBounds = new Rect();
+        // If orientation is respected when insets are applied, then stableBounds will be empty.
         boolean orientationRespectedWithInsets =
-                orientationRespectedWithInsets(parentBounds, containerBounds);
+                orientationRespectedWithInsets(parentBounds, stableBounds);
         if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) {
             // No need to letterbox because of fixed orientation. Display will handle
             // fixed-orientation requests and a display rotation is enough to respect requested
@@ -7536,71 +7580,68 @@
             return;
         }
 
-        // TODO(b/182268157) merge aspect ratio logic here and in
-        // {@link ActivityRecord#applyAspectRatio}
-        // if no aspect ratio constraints are provided, parent aspect ratio is used
-        float aspectRatio = computeAspectRatio(parentBounds);
+        // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
+        // bounds or stable bounds to unify aspect ratio logic.
+        final Rect parentBoundsWithInsets = orientationRespectedWithInsets
+                ? newParentConfig.windowConfiguration.getAppBounds() : stableBounds;
+        final Rect containingBounds = new Rect();
+        final Rect containingBoundsWithInsets = new Rect();
+        // Need to shrink the containing bounds into a square because the parent orientation
+        // does not match the activity requested orientation.
+        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+            // Landscape is defined as width > height. Make the container respect landscape
+            // orientation by shrinking height to one less than width. Landscape activity will be
+            // vertically centered within parent bounds with insets, so position vertical bounds
+            // within parent bounds with insets to prevent insets from unnecessarily trimming
+            // vertical bounds.
+            final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1,
+                    parentBoundsWithInsets.bottom);
+            containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,
+                    bottom);
+            containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
+                    parentBoundsWithInsets.right, bottom);
+        } else {
+            // Portrait is defined as width <= height. Make the container respect portrait
+            // orientation by shrinking width to match height. Portrait activity will be
+            // horizontally centered within parent bounds with insets, so position horizontal bounds
+            // within parent bounds with insets to prevent insets from unnecessarily trimming
+            // horizontal bounds.
+            final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(),
+                    parentBoundsWithInsets.right);
+            containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,
+                    parentBounds.bottom);
+            containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
+                    right, parentBoundsWithInsets.bottom);
+        }
+
+        // Store the current bounds to be able to revert to size compat mode values below if needed.
+        final Rect prevResolvedBounds = new Rect(resolvedBounds);
+        resolvedBounds.set(containingBounds);
 
         // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
         // set-fixed-orientation-letterbox-aspect-ratio.
         final float letterboxAspectRatioOverride =
                 mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
-        aspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
-                ? letterboxAspectRatioOverride : aspectRatio;
+        final float desiredAspectRatio =
+                letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+                        ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
+        // Apply aspect ratio to resolved bounds
+        mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
+                containingBounds, desiredAspectRatio, true);
 
-        // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
-        // order to use the extra available space.
-        final float maxAspectRatio = info.getMaxAspectRatio();
-        final float minAspectRatio = info.getMinAspectRatio();
-        if (aspectRatio > maxAspectRatio && maxAspectRatio != 0) {
-            aspectRatio = maxAspectRatio;
-        } else if (aspectRatio < minAspectRatio) {
-            aspectRatio = minAspectRatio;
-        }
-
-        // Store the current bounds to be able to revert to size compat mode values below if needed.
-        final Rect prevResolvedBounds = new Rect(resolvedBounds);
-
-        // Compute other dimension based on aspect ratio. Use bounds intersected with insets, stored
-        // in containerBounds after calling {@link ActivityRecord#orientationRespectedWithInsets()},
-        // to ensure that aspect ratio is respected after insets are applied.
-        int activityWidth;
-        int activityHeight;
+        // Vertically center if orientation is landscape. Center within parent bounds with insets
+        // to ensure that insets do not trim height. Bounds will later be horizontally centered in
+        // {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
-            activityWidth = parentBounds.width();
-            // Compute height from stable bounds width to ensure orientation respected after insets.
-            activityHeight = (int) Math.rint(containerBounds.width() / aspectRatio);
-            // Landscape is defined as width > height. To ensure activity is landscape when aspect
-            // ratio is close to 1, reduce the height by one pixel.
-            if (activityWidth == activityHeight) {
-                activityHeight -= 1;
-            }
-            // Center vertically within stable bounds in landscape to ensure insets do not trim
-            // height.
-            final int top = containerBounds.centerY() - activityHeight / 2;
-            resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + activityHeight);
-        } else {
-            activityHeight = parentBounds.height();
-            // Compute width from stable bounds height to ensure orientation respected after insets.
-            activityWidth = (int) Math.rint(containerBounds.height() / aspectRatio);
-            // Center horizontally in portrait. For now, align to left and allow
-            // {@link ActivityRecord#updateResolvedBoundsHorizontalPosition()} to center
-            // horizontally. Exclude left insets from parent to ensure cutout does not trim width.
-            final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
-            resolvedBounds.set(parentAppBounds.left, parentBounds.top,
-                    parentAppBounds.left + activityWidth, parentBounds.bottom);
+            final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
+            resolvedBounds.offset(0, offsetY);
         }
 
         if (mCompatDisplayInsets != null) {
             mCompatDisplayInsets.getBoundsByRotation(
                     mTmpBounds, newParentConfig.windowConfiguration.getRotation());
-            // Insets may differ between different rotations, for example in the case of a display
-            // cutout. To ensure consistent bounds across rotations, compare the activity dimensions
-            // minus insets from the rotation the compat bounds were computed in.
-            Task.intersectWithInsetsIfFits(mTmpBounds, parentBounds,
-                    mCompatDisplayInsets.mStableInsets[mCompatDisplayInsets.mOriginalRotation]);
-            if (activityWidth != mTmpBounds.width()
-                    || activityHeight != mTmpBounds.height()) {
+            if (resolvedBounds.width() != mTmpBounds.width()
+                    || resolvedBounds.height() != mTmpBounds.height()) {
                 // The app shouldn't be resized, we only do fixed orientation letterboxing if the
                 // compat bounds are also from the same fixed orientation letterbox. Otherwise,
                 // clear the fixed orientation bounds to show app in size compat mode.
@@ -7636,8 +7677,6 @@
         // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
         if (!mTmpBounds.isEmpty()) {
             resolvedBounds.set(mTmpBounds);
-            // Exclude the horizontal decor area.
-            resolvedBounds.left = parentAppBounds.left;
         }
         if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
             // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
@@ -7698,13 +7737,6 @@
             mIsAspectRatioApplied =
                     applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
         }
-        // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
-        // the container app bounds. Otherwise the entire container bounds are available.
-        final boolean fillContainer = resolvedBounds.equals(containingBounds);
-        if (!fillContainer) {
-            // The horizontal position should not cover insets.
-            resolvedBounds.left = containingAppBounds.left;
-        }
 
         // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
         // are calculated in compat container space. The actual position on screen will be applied
@@ -7771,6 +7803,7 @@
         // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
         // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
         // Above coordinates are in "@" space, now place "*" and "#" to screen space.
+        final boolean fillContainer = resolvedBounds.equals(containingBounds);
         final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
         final int screenPosY = containerBounds.top;
         if (screenPosX != 0 || screenPosY != 0) {
@@ -8012,6 +8045,12 @@
         return true;
     }
 
+    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+            Rect containingBounds) {
+        return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
+                0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
+    }
+
     /**
      * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
      * made to outBounds.
@@ -8020,17 +8059,19 @@
      */
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
     private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
-            Rect containingBounds) {
+            Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
         final float maxAspectRatio = info.getMaxAspectRatio();
         final Task rootTask = getRootTask();
         final float minAspectRatio = info.getMinAspectRatio();
 
         if (task == null || rootTask == null
-                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
-                || (maxAspectRatio == 0 && minAspectRatio == 0)
+                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
+                && !fixedOrientationLetterboxed)
+                || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
                 || isInVrUiMode(getConfiguration())) {
-            // We don't enforce aspect ratio if the activity task is in multiwindow unless it
-            // is in size-compat mode. We also don't set it if we are in VR mode.
+            // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
+            // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
+            // are in VR mode.
             return false;
         }
 
@@ -8038,20 +8079,30 @@
         final int containingAppHeight = containingAppBounds.height();
         final float containingRatio = computeAspectRatio(containingAppBounds);
 
+        if (desiredAspectRatio < 1) {
+            desiredAspectRatio = containingRatio;
+        }
+
+        if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
+            desiredAspectRatio = maxAspectRatio;
+        } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
+            desiredAspectRatio = minAspectRatio;
+        }
+
         int activityWidth = containingAppWidth;
         int activityHeight = containingAppHeight;
 
-        if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
+        if (containingRatio > desiredAspectRatio) {
             if (containingAppWidth < containingAppHeight) {
                 // Width is the shorter side, so we use that to figure-out what the max. height
                 // should be given the aspect ratio.
-                activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
+                activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
             } else {
                 // Height is the shorter side, so we use that to figure-out what the max. width
                 // should be given the aspect ratio.
-                activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
+                activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
             }
-        } else if (containingRatio < minAspectRatio) {
+        } else if (containingRatio < desiredAspectRatio) {
             boolean adjustWidth;
             switch (getRequestedConfigurationOrientation()) {
                 case ORIENTATION_LANDSCAPE:
@@ -8079,9 +8130,9 @@
                     break;
             }
             if (adjustWidth) {
-                activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
+                activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
             } else {
-                activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
+                activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
             }
         }
 
@@ -8105,6 +8156,13 @@
         }
         outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
 
+        // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
+        // container app bounds. Otherwise the entire container bounds are available.
+        if (!outBounds.equals(containingBounds)) {
+            // The horizontal position should not cover insets (e.g. display cutout).
+            outBounds.left = containingAppBounds.left;
+        }
+
         return true;
     }
 
@@ -9071,7 +9129,7 @@
                 record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
                 false /*isNotInRecents*/,
                 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
-                record.mStartBounds, task.getTaskInfo());
+                record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c881359..3bc6435 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -24,6 +24,7 @@
 import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
 import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
 import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_PERMISSION_DENIED;
 import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
 import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
 import static android.app.ActivityManager.START_SUCCESS;
@@ -193,7 +194,6 @@
     private Task mTargetTask;
     private boolean mMovedToFront;
     private boolean mNoAnimation;
-    private boolean mKeepCurTransition;
     private boolean mAvoidMoveToFront;
     private boolean mFrozeTaskList;
     private boolean mTransientLaunch;
@@ -592,7 +592,6 @@
         mTargetRootTask = starter.mTargetRootTask;
         mMovedToFront = starter.mMovedToFront;
         mNoAnimation = starter.mNoAnimation;
-        mKeepCurTransition = starter.mKeepCurTransition;
         mAvoidMoveToFront = starter.mAvoidMoveToFront;
         mFrozeTaskList = starter.mFrozeTaskList;
 
@@ -744,7 +743,7 @@
                 Slog.w(TAG, "Unable to find app for caller " + mRequest.caller + " (pid="
                         + mRequest.callingPid + ") when starting: " + mRequest.intent.toString());
                 SafeActivityOptions.abort(mRequest.activityOptions);
-                return ActivityManager.START_PERMISSION_DENIED;
+                return START_PERMISSION_DENIED;
             }
         }
 
@@ -858,7 +857,7 @@
             } else {
                 Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
                         + ") when starting: " + intent.toString());
-                err = ActivityManager.START_PERMISSION_DENIED;
+                err = START_PERMISSION_DENIED;
             }
         }
 
@@ -1707,6 +1706,8 @@
 
         mIntent.setFlags(mLaunchFlags);
 
+        // Get top task at beginning because the order may be changed when reusing existing task.
+        final Task prevTopTask = mPreferredTaskDisplayArea.getFocusedRootTask();
         final Task reusedTask = getReusableTask();
 
         // If requested, freeze the task list
@@ -1786,24 +1787,23 @@
                     UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
                     resultToUid /*visible*/, true /*direct*/);
         }
+        final Task startedTask = mStartActivity.getTask();
         if (newTask) {
-            EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
-                    mStartActivity.getTask().mTaskId);
+            EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);
         }
-        mStartActivity.logStartActivity(
-                EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
+        mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
 
         mStartActivity.getTaskFragment().clearLastPausedActivity();
 
         mRootWindowContainer.startPowerModeLaunchIfNeeded(
                 false /* forceSend */, mStartActivity);
 
+        final boolean isTaskSwitch = startedTask != prevTopTask;
         mTargetRootTask.startActivityLocked(mStartActivity,
                 topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
-                mKeepCurTransition, mOptions, sourceRecord);
+                isTaskSwitch, mOptions, sourceRecord);
         if (mDoResume) {
-            final ActivityRecord topTaskActivity =
-                    mStartActivity.getTask().topRunningActivityLocked();
+            final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
             if (!mTargetRootTask.isTopActivityFocusable()
                     || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                     && mStartActivity != topTaskActivity)) {
@@ -1837,8 +1837,8 @@
         mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
 
         // Update the recent tasks list immediately when the activity starts
-        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
-        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
+        mSupervisor.mRecentTasks.add(startedTask);
+        mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
                 mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);
 
         return START_SUCCESS;
@@ -1952,10 +1952,41 @@
             }
         }
 
+        if (mInTaskFragment != null && mInTaskFragment.getTask() != null) {
+            final int hostUid = mInTaskFragment.getTask().effectiveUid;
+            final int embeddingUid = targetTask != null ? targetTask.effectiveUid : r.getUid();
+            if (!canTaskBeEmbedded(hostUid, embeddingUid)) {
+                Slog.e(TAG, "Cannot embed activity to a task owned by " + hostUid + " targetTask= "
+                        + targetTask);
+                return START_PERMISSION_DENIED;
+            }
+        }
+
         return START_SUCCESS;
     }
 
     /**
+     * Return {@code true} if the {@param task} can embed another task.
+     * @param hostUid the uid of the host task
+     * @param embeddedUid the uid of the task the are going to be embedded
+     */
+    private boolean canTaskBeEmbedded(int hostUid, int embeddedUid) {
+        // Allowing the embedding if the task is owned by system.
+        if (hostUid == Process.SYSTEM_UID) {
+            return true;
+        }
+
+        // Allowing embedding if the host task is owned by an app that has the ACTIVITY_EMBEDDING
+        // permission
+        if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, hostUid) == PERMISSION_GRANTED) {
+            return true;
+        }
+
+        // Allowing embedding if it is from the same app that owned the task
+        return hostUid == embeddedUid;
+    }
+
+    /**
      * Prepare the target task to be reused for this launch, which including:
      * - Position the target task on valid root task on preferred display.
      * - Comply to the specified activity launch flags
@@ -2246,7 +2277,6 @@
         mTargetTask = null;
         mMovedToFront = false;
         mNoAnimation = false;
-        mKeepCurTransition = false;
         mAvoidMoveToFront = false;
         mFrozeTaskList = false;
         mTransientLaunch = false;
@@ -2354,6 +2384,11 @@
             }
             mTransientLaunch = mOptions.getTransientLaunch();
             mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
+
+            if (inTaskFragment == null) {
+                inTaskFragment = TaskFragment.fromTaskFragmentToken(
+                        mOptions.getLaunchTaskFragmentToken(), mService);
+            }
         }
 
         mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
@@ -2647,7 +2682,7 @@
                             && mTargetRootTask != intentTask.getParent().asTask()) {
                         intentTask.getParent().positionChildAt(POSITION_TOP, intentTask,
                                 false /* includingParents */);
-                        intentTask = intentTask.getParent().asTask();
+                        intentTask = intentTask.getParent().asTaskFragment().getTask();
                     }
                     // If the task is in multi-windowing mode, the activity may already be on
                     // the top (visible to user but not the global top), then the result code
@@ -2736,31 +2771,6 @@
         mIntentDelivered = true;
     }
 
-    /**
-     * Return {@code true} if the {@param task} has child {@code TaskFragment}s and the
-     * {@param activity} can be embedded in. Otherwise, return {@code false}
-     */
-    private boolean canActivityBeEmbedded(@NonNull ActivityRecord activity, @NonNull Task task) {
-        if (task.isLeafTaskFragment()) {
-            return false;
-        }
-
-        final int taskUid = task.effectiveUid;
-        // Allowing the activity be embedded into leaf TaskFragment if the task is owned by system.
-        if (taskUid == Process.SYSTEM_UID) {
-            return true;
-        }
-
-        // Allowing embedding if the task is owned by an app that has the ACTIVITY_EMBEDDING
-        // permission
-        if (mService.checkPermission(ACTIVITY_EMBEDDING, -1, taskUid) == PERMISSION_GRANTED) {
-            return true;
-        }
-
-        // Allowing embedding if the activity is from the same app that owned the task
-        return activity.isUid(taskUid);
-    }
-
     private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
         TaskFragment newParent = task;
         if (mInTaskFragment != null) {
@@ -2772,9 +2782,10 @@
             } else {
                 newParent = mInTaskFragment;
             }
-        } else if (canActivityBeEmbedded(mStartActivity, task)) {
+        } else {
             // Use the child TaskFragment (if any) as the new parent if the activity can be embedded
-            final ActivityRecord top = task.topRunningActivity();
+            final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
+                    false /* includingEmbeddedTask */);
             newParent = top != null ? top.getTaskFragment() : task;
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 1759cde..5174a38 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -621,4 +621,7 @@
      */
     public abstract boolean hasSystemAlertWindowPermission(int callingUid, int callingPid,
             String callingPackage);
+
+    /** Called when the device is waking up */
+    public abstract void notifyWakingUp();
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 48a6626..19cf14f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -64,6 +64,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_WAKE;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
@@ -1907,15 +1908,15 @@
 
         if (r.moveFocusableActivityToTop("setFocusedTask")) {
             mRootWindowContainer.resumeFocusedTasksTopActivities();
-        } else if (touchedActivity != null && touchedActivity != r
-                && touchedActivity.getTask() == r.getTask()
-                && touchedActivity.getTaskFragment() != r.getTaskFragment()) {
-            // Set the focused app directly since the focused window is not on the
-            // top-most TaskFragment of the top-most Task
-            final DisplayContent displayContent = touchedActivity.getDisplayContent();
-            displayContent.setFocusedApp(touchedActivity);
-            mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
-                    true /* updateInputWindows */);
+        } else if (touchedActivity != null && touchedActivity.isFocusable()) {
+            final TaskFragment parent = touchedActivity.getTaskFragment();
+            if (parent != null && parent.isEmbedded()) {
+                // Set the focused app directly if the focused window is currently embedded
+                final DisplayContent displayContent = touchedActivity.getDisplayContent();
+                displayContent.setFocusedApp(touchedActivity);
+                mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+                        true /* updateInputWindows */);
+            }
         }
     }
 
@@ -6500,6 +6501,13 @@
             return ActivityTaskManagerService.this.hasSystemAlertWindowPermission(callingUid,
                     callingPid, callingPackage);
         }
+
+        @Override
+        public void notifyWakingUp() {
+            // Start a transition for waking. This is needed for showWhenLocked activities.
+            getTransitionController().requestTransitionIfNeeded(TRANSIT_WAKE, 0 /* flags */,
+                    null /* trigger */, mRootWindowContainer.getDefaultDisplay());
+        }
     }
 
     final class PackageConfigurationUpdaterImpl implements
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index f728a48..50ac433 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -352,6 +352,12 @@
      */
     private int mVisibilityTransactionDepth;
 
+    /**
+     * Whether to the visibility updates that started from {@code RootWindowContainer} should be
+     * deferred.
+     */
+    private boolean mDeferRootVisibilityUpdate;
+
     private ActivityMetricsLogger mActivityMetricsLogger;
 
     /** Check if placing task or activity on specified display is allowed. */
@@ -841,6 +847,10 @@
                         proc.getThread(), r.appToken);
 
                 final boolean isTransitionForward = r.isTransitionForward();
+                IBinder fragmentToken = null;
+                if (r.getTaskFragment().getTaskFragmentOrganizerPid() == r.getPid()) {
+                    fragmentToken = r.getTaskFragment().getFragmentToken();
+                }
                 clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                         System.identityHashCode(r), r.info,
                         // TODO: Have this take the merged configuration instead of separate global
@@ -852,7 +862,7 @@
                         r.takeOptions(), isTransitionForward,
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                         r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
-                        r.getLaunchedFromBubble()));
+                        r.getLaunchedFromBubble(), fragmentToken));
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
@@ -1551,7 +1561,13 @@
             return;
         }
         if (task.isVisible()) {
-            mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+            if (mService.getTransitionController().isCollecting()) {
+                // We don't want the finishing to change the transition ready state since there will
+                // not be corresponding setReady for finishing.
+                mService.getTransitionController().collectExistenceChange(task);
+            } else {
+                mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+            }
         } else {
             // Removing a non-visible task doesn't require a transition, but if there is one
             // collecting, this should be a member just in case.
@@ -2287,6 +2303,14 @@
         return mVisibilityTransactionDepth > 0;
     }
 
+    void setDeferRootVisibilityUpdate(boolean deferUpdate) {
+        mDeferRootVisibilityUpdate = deferUpdate;
+    }
+
+    boolean isRootVisibilityUpdateDeferred() {
+        return mDeferRootVisibilityUpdate;
+    }
+
     /**
      * Called when the state or visibility of an attached activity is changed.
      *
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c869ec6..d6b0086 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -464,7 +464,8 @@
         }
         final RemoteAnimationAdapter adapter =
                 getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
-        if (adapter != null) {
+        if (adapter != null
+                && mDisplayContent.mAppTransition.getRemoteAnimationController() == null) {
             mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
         }
     }
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index 0363944..41d9dbf 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.PowerManager.THERMAL_STATUS_CRITICAL;
 import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
 
 import android.content.BroadcastReceiver;
@@ -45,6 +46,7 @@
     private final Object mLock = new Object();
     private volatile boolean mBlurEnabled;
     private boolean mInPowerSaveMode;
+    private boolean mCriticalThermalStatus;
     private boolean mBlurDisabledSetting;
     private boolean mTunnelModeEnabled = false;
 
@@ -89,6 +91,12 @@
                 });
         mBlurDisabledSetting = getBlurDisabledSetting();
 
+        powerManager.addThermalStatusListener((status) -> {
+            mCriticalThermalStatus = status >= THERMAL_STATUS_CRITICAL;
+            updateBlurEnabled();
+        });
+        mCriticalThermalStatus = powerManager.getCurrentThermalStatus() >= THERMAL_STATUS_CRITICAL;
+
         TunnelModeEnabledListener.register(mTunnelModeListener);
 
         updateBlurEnabled();
@@ -112,7 +120,7 @@
     private void updateBlurEnabled() {
         synchronized (mLock) {
             final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
-                    && !mInPowerSaveMode && !mTunnelModeEnabled;
+                    && !mInPowerSaveMode && !mTunnelModeEnabled && !mCriticalThermalStatus;
             if (mBlurEnabled == newEnabled) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a6e8a03..63aeea8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -133,7 +133,6 @@
 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
@@ -295,6 +294,22 @@
      */
     private final SurfaceControl mWindowingLayer;
 
+    /**
+     * The window token of the layer of the hierarchy to mirror, or null if this DisplayContent
+     * is not being used for layer mirroring.
+     */
+    @VisibleForTesting IBinder mTokenToMirror = null;
+
+    /**
+     * The surface for mirroring the contents of this hierarchy.
+     */
+    private SurfaceControl mMirroredSurface = null;
+
+    /**
+     * The last bounds of the DisplayArea to mirror.
+     */
+    private Rect mLastMirroredDisplayAreaBounds = null;
+
     // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
     // on the IME target. We mainly have this container grouping so we can keep track of all the IME
     // window containers together and move them in-sync if/when needed. We use a subclass of
@@ -430,6 +445,7 @@
     // Accessed directly by all users.
     private boolean mLayoutNeeded;
     int pendingLayoutChanges;
+    boolean mLayoutAndAssignWindowLayersScheduled;
 
     /**
      * Used to gate application window layout until we have sent the complete configuration.
@@ -502,11 +518,6 @@
     WindowState mCurrentFocus = null;
 
     /**
-     * The last focused window that we've notified the client that the focus is changed.
-     */
-    WindowState mLastFocus = null;
-
-    /**
      * The foreground app of this display. Windows below this app cannot be the focused window. If
      * the user taps on the area outside of the task of the focused app, we will notify AM about the
      * new task the user wants to interact with.
@@ -733,13 +744,20 @@
 
         // When switching the app task, we keep the IME window visibility for better
         // transitioning experiences.
-        // However, in case IME created a child window without dismissing during the task
-        // switching to keep the window focus because IME window has higher window hierarchy,
-        // we don't give it focus if the next IME layering target doesn't request IME visible.
+        // However, in case IME created a child window or the IME selection dialog without
+        // dismissing during the task switching to keep the window focus because IME window has
+        // higher window hierarchy, we don't give it focus if the next IME layering target
+        // doesn't request IME visible.
         if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
                 || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
             return false;
         }
+        if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG && mImeLayeringTarget != null
+                && !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME)
+                && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
+                ANIMATION_TYPE_APP_TRANSITION)) {
+            return false;
+        }
 
         final ActivityRecord activity = w.mActivityRecord;
 
@@ -769,10 +787,19 @@
                 return true;
             }
 
-            if (focusedApp.getTask() == activity.getTask()
-                    && focusedApp.getTaskFragment() != activity.getTaskFragment()) {
-                // Do not use the activity window of another TaskFragment in the same leaf Task
-                return false;
+            // If the candidate activity is currently being embedded in the focused task, the
+            // activity cannot be focused unless it is on the same TaskFragment as the focusedApp's.
+            TaskFragment parent = activity.getTaskFragment();
+            if (parent != null && parent.isEmbedded()) {
+                Task hostTask = focusedApp.getTask();
+                if (hostTask.isEmbedded()) {
+                    // Use the hosting task if the current task is embedded.
+                    hostTask = hostTask.getParent().asTaskFragment().getTask();
+                }
+                if (activity.isDescendantOf(hostTask)
+                        && activity.getTaskFragment() != focusedApp.getTaskFragment()) {
+                    return false;
+                }
             }
         }
 
@@ -1109,6 +1136,10 @@
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
 
         mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+        // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring
+        // to capture the contents of a DisplayArea.
+        startMirrorIfNeeded();
     }
 
     boolean isReady() {
@@ -1239,12 +1270,6 @@
                 // removing from parent.
                 token.getParent().removeChild(token);
             }
-            if (token.hasChild(prevDc.mLastFocus)) {
-                // If the reparent window token contains previous display's last focus window, means
-                // it will end up to gain window focus on the target display, so it should not be
-                // notified that it lost focus from the previous display.
-                prevDc.mLastFocus = null;
-            }
         }
 
         addWindowToken(token.token, token);
@@ -2469,6 +2494,25 @@
         // Update IME parent if needed.
         updateImeParent();
 
+        // Update mirroring surface for MediaProjection, if this DisplayContent is being used
+        // for layer mirroring.
+        if (mMirroredSurface != null) {
+            // Retrieve the size of the DisplayArea to mirror, and continue with the update if the
+            // bounds have changed.
+            final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+                    mTokenToMirror);
+            if (wc != null && mLastMirroredDisplayAreaBounds != null) {
+                // Retrieve the size of the DisplayArea to mirror, and continue with the update
+                // if the bounds or orientation has changed.
+                final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
+                int displayAreaOrientation = wc.getDisplayContent().getOrientation();
+                if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
+                        || lastOrientation != displayAreaOrientation) {
+                    updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
+                }
+            }
+        }
+
         if (lastOrientation != getConfiguration().orientation) {
             getMetricsLogger().write(
                     new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
@@ -3199,9 +3243,6 @@
         pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
 
         pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
-        if (mLastFocus != mCurrentFocus) {
-            pw.print("  mLastFocus="); pw.println(mLastFocus);
-        }
         pw.print("  mFocusedApp="); pw.println(mFocusedApp);
         if (mFixedRotationLaunchingApp != null) {
             pw.println("  mFixedRotationLaunchingApp=" + mFixedRotationLaunchingApp);
@@ -3432,15 +3473,12 @@
             }
         }
 
-        onWindowFocusChanged(oldFocus, newFocus);
-
-        int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
+        getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
 
         if (imWindowChanged && oldFocus != mInputMethodWindow) {
             // Focus of the input method window changed. Perform layout if needed.
             if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                 performLayout(true /*initial*/,  updateInputWindows);
-                focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
             } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                 // Client will do the layout, but we need to assign layers
                 // for handleNewWindowLocked() below.
@@ -3448,16 +3486,6 @@
             }
         }
 
-        if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
-            // The change in focus caused us to need to do a layout.  Okay.
-            setLayoutNeeded();
-            if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
-                performLayout(true /*initial*/, updateInputWindows);
-            } else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) {
-                mWmService.mRoot.performSurfacePlacement();
-            }
-        }
-
         if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
             // If we defer assigning layers, then the caller is responsible for doing this part.
             getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
@@ -3484,7 +3512,6 @@
                     mWmService.mAccessibilityController));
         }
 
-        mLastFocus = mCurrentFocus;
         return true;
     }
 
@@ -3492,20 +3519,6 @@
         accessibilityController.onWindowFocusChangedNot(getDisplayId());
     }
 
-    private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
-        final Task focusedTask = newFocus != null ? newFocus.getTask() : null;
-        final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null;
-        if (focusedTask == unfocusedTask) {
-            return;
-        }
-        if (focusedTask != null) {
-            focusedTask.onWindowFocusChanged(true /* hasFocus */);
-        }
-        if (unfocusedTask != null) {
-            unfocusedTask.onWindowFocusChanged(false /* hasFocus */);
-        }
-    }
-
     /**
      * Set the new focused app to this display.
      *
@@ -3529,7 +3542,14 @@
         }
         ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "setFocusedApp %s displayId=%d Callers=%s",
                 newFocus, getDisplayId(), Debug.getCallers(4));
+        final Task oldTask = mFocusedApp != null ? mFocusedApp.getTask() : null;
+        final Task newTask = newFocus != null ? newFocus.getTask() : null;
         mFocusedApp = newFocus;
+        if (oldTask != newTask) {
+            if (oldTask != null) oldTask.onAppFocusChanged(false);
+            if (newTask != null) newTask.onAppFocusChanged(true);
+        }
+
         getInputMonitor().setFocusedAppLw(newFocus);
         updateTouchExcludeRegion();
         return true;
@@ -3993,7 +4013,9 @@
         // Update Ime parent when IME insets leash created or the new IME layering target might
         // updated from setImeLayeringTarget, which is the best time that default IME visibility
         // has been settled down after IME control target changed.
-        if (prevImeControlTarget != mImeControlTarget || forceUpdateImeParent) {
+        final boolean imeParentChanged =
+                prevImeControlTarget != mImeControlTarget || forceUpdateImeParent;
+        if (imeParentChanged) {
             updateImeParent();
         }
 
@@ -4001,7 +4023,7 @@
         final IBinder token = win != null ? win.mClient.asBinder() : null;
         // Note: not allowed to call into IMMS with the WM lock held, hence the post.
         mWmService.mH.post(() ->
-                InputMethodManagerInternal.get().reportImeControl(token)
+                InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged)
         );
     }
 
@@ -4225,7 +4247,6 @@
         if (DEBUG_INPUT_METHOD) {
             Slog.i(TAG_WM, "Desired input method target: " + imFocus);
             Slog.i(TAG_WM, "Current focus: " + mCurrentFocus + " displayId=" + mDisplayId);
-            Slog.i(TAG_WM, "Last focus: " + mLastFocus + " displayId=" + mDisplayId);
         }
 
         if (DEBUG_INPUT_METHOD) {
@@ -4350,6 +4371,7 @@
                     mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                     true /* inTraversal, must call performTraversalInTrans... below */);
         }
+        updateMirroring();
 
         final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
         if (wallpaperVisible != mLastWallpaperVisible) {
@@ -4604,7 +4626,9 @@
                 return true;
             }
 
-            if (task.isOrganized()) {
+            // TODO(b/165794880): Freeform task organizer doesn't support drag-resize yet. Remove
+            // the special case when it does.
+            if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
                 return true;
             }
 
@@ -4957,10 +4981,18 @@
         }
     }
 
+    /**
+     * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
+     */
+    @Deprecated
     void prepareAppTransition(@WindowManager.TransitionType int transit) {
         prepareAppTransition(transit, 0 /* flags */);
     }
 
+    /**
+     * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
+     */
+    @Deprecated
     void prepareAppTransition(@WindowManager.TransitionType int transit,
             @WindowManager.TransitionFlags int flags) {
         final boolean prepared = mAppTransition.prepareAppTransition(transit, flags);
@@ -4973,7 +5005,8 @@
      * Helper that both requests a transition (using the new transition system) and prepares
      * the legacy transition system. Use this when both systems have the same start-point.
      *
-     * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer)
+     * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer,
+     *      WindowContainer)
      * @see AppTransition#prepareAppTransition
      */
     void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit,
@@ -5869,6 +5902,133 @@
         return mSandboxDisplayApis;
     }
 
+    /**
+     * Start mirroring to this DisplayContent if it does not have its own content. Captures the
+     * content of a WindowContainer indicated by a WindowToken. If unable to start mirroring, falls
+     * back to original MediaProjection approach.
+     */
+    private void startMirrorIfNeeded() {
+        // Only mirror if this display does not have its own content.
+        if (mLastHasContent) {
+            return;
+        }
+        // Given the WindowToken of the DisplayArea to mirror, retrieve the associated
+        // SurfaceControl.
+        IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
+                mDisplayId);
+
+        if (tokenToMirror == null) {
+            // This DisplayContent instance is not involved in layer mirroring. If the display
+            // has been created for capturing, fall back to prior MediaProjection approach.
+            return;
+        }
+        final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+                tokenToMirror);
+        if (wc == null) {
+            // Un-set the window token to mirror for this VirtualDisplay, to fall back to the
+            // original MediaProjection approach.
+            mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null);
+            return;
+        }
+        SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
+
+        // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
+        mMirroredSurface = SurfaceControl.mirrorSurface(sc);
+        SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
+                // Set the mMirroredSurface's parent to the root SurfaceControl for this
+                // DisplayContent. This brings the new mirrored hierarchy under this DisplayContent,
+                // so SurfaceControl will write the layers of this hierarchy to the output surface
+                // provided by the app.
+                .reparent(mMirroredSurface, mSurfaceControl)
+                // Reparent the SurfaceControl of this DisplayContent to null, to prevent content
+                // being added to it. This ensures that no app launched explicitly on the
+                // VirtualDisplay will show up as part of the mirrored content.
+                .reparent(mWindowingLayer, null);
+        // Retrieve the size of the DisplayArea to mirror.
+        updateMirroredSurface(transaction, wc.getDisplayContent().getBounds());
+        mTokenToMirror = tokenToMirror;
+
+        // No need to clean up. In SurfaceFlinger, parents hold references to their children. The
+        // mirrored SurfaceControl is alive since the parent DisplayContent SurfaceControl is
+        // holding a reference to it. Therefore, the mirrored SurfaceControl will be cleaned up
+        // when the VirtualDisplay is destroyed - which will clean up this DisplayContent.
+    }
+
+    /**
+     * Start or stop mirroring if this DisplayContent now has content, or no longer has content.
+     */
+    private void updateMirroring() {
+        if (mLastHasContent && mMirroredSurface != null) {
+            // Display now has content, so stop mirroring to it.
+            mWmService.mTransactionFactory.get()
+                    // Remove the reference to mMirroredSurface, to clean up associated memory.
+                    .remove(mMirroredSurface)
+                    // Reparent the SurfaceControl of this DisplayContent back to mSurfaceControl,
+                    // to allow content to be added to it. This allows this DisplayContent to stop
+                    // mirroring and show content normally.
+                    .reparent(mWindowingLayer, mSurfaceControl).apply();
+            // Stop mirroring by destroying the reference to the mirrored layer.
+            mMirroredSurface = null;
+            // Do not un-set the token, in case content is removed and mirroring should begin again.
+        } else if (!mLastHasContent && mMirroredSurface == null) {
+            // Display no longer has content, so start mirroring to it.
+            startMirrorIfNeeded();
+        }
+    }
+
+    /**
+     * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
+     * fit and centred in the output surface.
+     *
+     * @param transaction            the transaction to include transformations of mMirroredSurface
+     *                               to. Transaction is not applied before returning.
+     * @param displayAreaBounds      bounds of the DisplayArea to mirror to the surface provided by
+     *                               the app.
+     */
+    @VisibleForTesting
+    void updateMirroredSurface(SurfaceControl.Transaction transaction,
+            Rect displayAreaBounds) {
+        // Retrieve the default size of the surface the app provided to
+        // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
+        // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
+        // it writes the mirrored layers to the buffers.
+        final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
+                mDisplayId);
+
+        // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
+        // output surface.
+        float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
+        float scaleY = surfaceSize.y / (float) displayAreaBounds.height();
+        float scale = Math.min(scaleX, scaleY);
+        int scaledWidth = Math.round(scale * (float) displayAreaBounds.width());
+        int scaledHeight = Math.round(scale * (float) displayAreaBounds.height());
+
+        // Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored
+        // contents in the output surface.
+        int shiftedX = 0;
+        if (scaledWidth != surfaceSize.x) {
+            shiftedX = (surfaceSize.x - scaledWidth) / 2;
+        }
+        int shiftedY = 0;
+        if (scaledHeight != surfaceSize.y) {
+            shiftedY = (surfaceSize.y - scaledHeight) / 2;
+        }
+
+        transaction
+                // Crop the area to capture to exclude the 'extra' wallpaper that is used
+                // for parallax (b/189930234).
+                .setWindowCrop(mMirroredSurface, displayAreaBounds.width(),
+                        displayAreaBounds.height())
+                // Scale the root mirror SurfaceControl, based upon the size difference between the
+                // source (DisplayArea to capture) and output (surface the app reads images from).
+                .setMatrix(mMirroredSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
+                // Position needs to be updated when the mirrored DisplayArea has changed, since
+                // the content will no longer be centered in the output surface.
+                .setPosition(mMirroredSurface, shiftedX /* x */, shiftedY /* y */)
+                .apply();
+        mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds);
+    }
+
     /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
     class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 3df1bfc..801182c 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1984,11 +1984,7 @@
             mTopIsFullscreen = topIsFullscreen;
         }
 
-        if (updateSystemUiVisibilityLw()) {
-            // If the navigation bar has been hidden or shown, we need to do another
-            // layout pass to update that window.
-            changes |= FINISH_LAYOUT_REDO_LAYOUT;
-        }
+        updateSystemBarAttributes();
 
         if (mShowingDream != mLastShowingDream) {
             mLastShowingDream = mShowingDream;
@@ -2291,7 +2287,8 @@
         return width;
     }
 
-    private int getNavigationBarHeight(int rotation, int uiMode) {
+    @VisibleForTesting
+    int getNavigationBarHeight(int rotation, int uiMode) {
         if (INSETS_LAYOUT_GENERALIZATION) {
             if (mNavigationBar == null) {
                 return 0;
@@ -2527,18 +2524,13 @@
     /**
      * A new window has been focused.
      */
-    public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
+    public void focusChangedLw(WindowState lastFocus, WindowState newFocus) {
         mFocusedWindow = newFocus;
         mLastFocusedWindow = lastFocus;
         if (mDisplayContent.isDefaultDisplay) {
             mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
         }
-        if (updateSystemUiVisibilityLw()) {
-            // If the navigation bar has been hidden or shown, we need to do another
-            // layout pass to update that window.
-            return FINISH_LAYOUT_REDO_LAYOUT;
-        }
-        return 0;
+        updateSystemBarAttributes();
     }
 
     private void requestTransientBars(WindowState swipeTarget) {
@@ -2614,21 +2606,18 @@
         return mDisplayContent.getInsetsPolicy();
     }
 
-    void resetSystemUiVisibilityLw() {
+    void resetSystemBarAttributes() {
         mLastDisableFlags = 0;
-        updateSystemUiVisibilityLw();
+        updateSystemBarAttributes();
     }
 
-    /**
-     * @return {@code true} if the update may affect the layout.
-     */
-    boolean updateSystemUiVisibilityLw() {
+    void updateSystemBarAttributes() {
         // If there is no window focused, there will be nobody to handle the events
         // anyway, so just hang on in whatever state we're in until things settle down.
         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
                 : mTopFullscreenOpaqueWindowState;
         if (winCandidate == null) {
-            return false;
+            return;
         }
 
         // The immersive mode confirmation should never affect the system bar visibility, otherwise
@@ -2644,7 +2633,7 @@
                     : lastFocusCanReceiveKeys ? mLastFocusedWindow
                             : mTopFullscreenOpaqueWindowState;
             if (winCandidate == null) {
-                return false;
+                return;
             }
         }
         final WindowState win = winCandidate;
@@ -2683,7 +2672,7 @@
                 && Objects.equals(mFocusedApp, focusedApp)
                 && mLastFocusIsFullscreen == isFullscreen
                 && Arrays.equals(mLastStatusBarAppearanceRegions, appearanceRegions)) {
-            return false;
+            return;
         }
         if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
                 && ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
@@ -2701,7 +2690,6 @@
         callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId,
                 appearance, appearanceRegions, isNavbarColorManagedByIme, behavior,
                 requestedVisibilities, focusedApp));
-        return true;
     }
 
     private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) {
@@ -2973,7 +2961,7 @@
                     return;
                 }
                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
-                updateSystemUiVisibilityLw();
+                updateSystemBarAttributes();
             }
         }
     };
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index d12d07a..d073f94 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -291,12 +291,14 @@
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder());
         }
+        mCallback.get().dragRecipientEntered(window);
     }
 
     void dragRecipientExited(IWindow window) {
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder());
         }
+        mCallback.get().dragRecipientExited(window);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index 53b6b41..eab3f10 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -66,10 +66,8 @@
         } else {
             mNavBarToken = null;
         }
-        // Do not fade notification shade when running fixed rotation (not frozen) because it may
-        // need to animate with the launching app.
-        final WindowState notificationShade = mFrozenTimeoutRunnable == null
-                ? displayPolicy.getNotificationShade() : null;
+        // Collect the target windows to fade out. The display won't wait for them to unfreeze.
+        final WindowState notificationShade = displayPolicy.getNotificationShade();
         displayContent.forAllWindows(w -> {
             if (w.mActivityRecord == null && w.mHasSurface && !w.mForceSeamlesslyRotate
                     && !w.mIsWallpaper && !w.mIsImWindow && w != navigationBar
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index eb5ab83..42c536b 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -38,6 +38,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
@@ -306,7 +307,10 @@
         boolean useSurfaceCrop = false;
         final Task task = w.getTask();
         if (task != null) {
-            if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+            // TODO(b/165794636): Remove the special case for freeform window once drag resizing is
+            // handled by WM shell.
+            if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
+                        && !task.inFreeformWindowingMode()) {
                 // If the window is in a TaskManaged by a TaskOrganizer then most cropping will
                 // be applied using the SurfaceControl hierarchy from the Organizer. This means
                 // we need to make sure that these changes in crop are reflected in the input
@@ -538,7 +542,8 @@
             if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
                 if (recentsAnimationController.updateInputConsumerForApp(
                         mRecentsAnimationInputConsumer.mWindowHandle)) {
-                    mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord);
+                    mRecentsAnimationInputConsumer.show(mInputTransaction,
+                            recentsAnimationController.getHighestLayerTask());
                     mAddRecentsAnimationInputConsumerHandle = false;
                 }
             }
@@ -648,6 +653,7 @@
                 || type == TYPE_DOCK_DIVIDER
                 || type == TYPE_ACCESSIBILITY_OVERLAY
                 || type == TYPE_INPUT_CONSUMER
-                || type == TYPE_VOICE_INTERACTION;
+                || type == TYPE_VOICE_INTERACTION
+                || type == TYPE_STATUS_BAR_ADDITIONAL;
     }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index d9112c5..53af563 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -30,10 +30,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
 
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.StatusBarManager;
@@ -138,12 +134,19 @@
             abortTransient();
         }
         mFocusedWin = focusedWin;
-        InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin);
-        InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin);
-        mStateController.onBarControlTargetChanged(statusControlTarget,
-                getFakeControlTarget(focusedWin, statusControlTarget),
+        final InsetsControlTarget statusControlTarget =
+                getStatusControlTarget(focusedWin, false /* fake */);
+        final InsetsControlTarget navControlTarget =
+                getNavControlTarget(focusedWin, false /* fake */);
+        mStateController.onBarControlTargetChanged(
+                statusControlTarget,
+                statusControlTarget == mDummyControlTarget
+                        ? getStatusControlTarget(focusedWin, true /* fake */)
+                        : null,
                 navControlTarget,
-                getFakeControlTarget(focusedWin, navControlTarget));
+                navControlTarget == mDummyControlTarget
+                        ? getNavControlTarget(focusedWin, true /* fake */)
+                        : null);
         mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR);
         mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR);
     }
@@ -215,7 +218,7 @@
     InsetsState getInsetsForWindow(WindowState target) {
         final InsetsState originalState = mStateController.getInsetsForWindow(target);
         final InsetsState state = adjustVisibilityForTransientTypes(originalState);
-        return adjustVisibilityForIme(target, state, state == originalState);
+        return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
     }
 
     /**
@@ -245,38 +248,16 @@
         return state;
     }
 
-    private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
+    // Navigation bar insets is always visible to IME.
+    private static InsetsState adjustVisibilityForIme(InsetsState originalState,
             boolean copyState) {
-        if (w.mIsImWindow) {
-            // Navigation bar insets is always visible to IME.
-            final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
-            if (originalNavSource != null && !originalNavSource.isVisible()) {
-                final InsetsState state = copyState ? new InsetsState(originalState)
-                        : originalState;
-                final InsetsSource navSource = new InsetsSource(originalNavSource);
-                navSource.setVisible(true);
-                state.addSource(navSource);
-                return state;
-            }
-        } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) {
-            // During switching tasks with gestural navigation, if the IME is attached to
-            // one app window on that time, even the next app window is behind the IME window,
-            // conceptually the window should not receive the IME insets if the next window is
-            // not eligible IME requester and ready to show IME on top of it.
-            final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
-            final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
-
-            if (originalImeSource != null && shouldImeAttachedToApp
-                    && (w.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS)
-                            || !w.getRequestedVisibility(ITYPE_IME))) {
-                final InsetsState state = copyState ? new InsetsState(originalState)
-                        : originalState;
-
-                final InsetsSource imeSource = new InsetsSource(originalImeSource);
-                imeSource.setVisible(false);
-                state.addSource(imeSource);
-                return state;
-            }
+        final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+        if (originalNavSource != null && !originalNavSource.isVisible()) {
+            final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
+            final InsetsSource navSource = new InsetsSource(originalNavSource);
+            navSource.setVisible(true);
+            state.addSource(navSource);
+            return state;
         }
         return originalState;
     }
@@ -330,13 +311,9 @@
         mShowingTransientTypes.clear();
     }
 
-    private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused,
-            InsetsControlTarget realControlTarget) {
-        return realControlTarget == mDummyControlTarget ? focused : null;
-    }
-
-    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin) {
-        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) {
+    private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
+            boolean fake) {
+        if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1 && !fake) {
             return mDummyControlTarget;
         }
         final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -354,7 +331,7 @@
             // we will dispatch the real visibility of status bar to the client.
             return null;
         }
-        if (forceShowsStatusBarTransiently()) {
+        if (forceShowsStatusBarTransiently() && !fake) {
             // Status bar is forcibly shown transiently, and its new visibility won't be
             // dispatched to the client so that we can keep the layout stable. We will dispatch the
             // fake control to the client, so that it can re-show the bar during this scenario.
@@ -379,13 +356,14 @@
                 && !win.inMultiWindowMode();
     }
 
-    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
+    private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin,
+            boolean fake) {
         final WindowState imeWin = mDisplayContent.mInputMethodWindow;
         if (imeWin != null && imeWin.isVisible()) {
             // Force showing navigation bar while IME is visible.
             return null;
         }
-        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) {
+        if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1 && !fake) {
             return mDummyControlTarget;
         }
         if (focusedWin == mPolicy.getNotificationShade()) {
@@ -402,7 +380,7 @@
             // bar, and we will dispatch the real visibility of navigation bar to the client.
             return null;
         }
-        if (forceShowsNavigationBarTransiently()) {
+        if (forceShowsNavigationBarTransiently() && !fake) {
             // Navigation bar is forcibly shown transiently, and its new visibility won't be
             // dispatched to the client so that we can keep the layout stable. We will dispatch the
             // fake control to the client, so that it can re-show the bar during this scenario.
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index cbd1314..f3e52f2 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -376,8 +376,11 @@
             return;
         }
         mClientVisible = clientVisible;
-        mDisplayContent.mWmService.mH.obtainMessage(
-                LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+        if (!mDisplayContent.mLayoutAndAssignWindowLayersScheduled) {
+            mDisplayContent.mLayoutAndAssignWindowLayersScheduled = true;
+            mDisplayContent.mWmService.mH.obtainMessage(
+                    LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+        }
         updateVisibility();
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 655007c..2c4adcb 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -385,7 +385,7 @@
         if (changed) {
             notifyInsetsChanged();
             mDisplayContent.updateSystemGestureExclusion();
-            mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
+            mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 672ebf1..d67d5fa 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -49,6 +49,7 @@
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+import android.view.WindowManager;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -158,6 +159,7 @@
         final boolean keyguardChanged = (keyguardShowing != mKeyguardShowing)
                 || (mKeyguardGoingAway && keyguardShowing && !aodChanged);
         if (!keyguardChanged && !aodChanged) {
+            setWakeTransitionReady();
             return;
         }
         EventLogTags.writeWmSetKeyguardShown(
@@ -203,6 +205,15 @@
         updateKeyguardSleepToken();
         mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
         InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */);
+        setWakeTransitionReady();
+    }
+
+    private void setWakeTransitionReady() {
+        if (mWindowManager.mAtmService.getTransitionController().getCollectingTransitionType()
+                == WindowManager.TRANSIT_WAKE) {
+            mWindowManager.mAtmService.getTransitionController().setReady(
+                    mRootWindowContainer.getDefaultDisplay());
+        }
     }
 
     /**
@@ -334,6 +345,7 @@
         for (int displayNdx = mRootWindowContainer.getChildCount() - 1;
              displayNdx >= 0; displayNdx--) {
             final DisplayContent display = mRootWindowContainer.getChildAt(displayNdx);
+            if (display.isRemoving() || display.isRemoved()) continue;
             final KeyguardDisplayState state = getDisplayState(display.mDisplayId);
             state.updateVisibility(this, display);
             requestDismissKeyguard |= state.mRequestDismissKeyguard;
@@ -366,15 +378,17 @@
             mService.deferWindowLayout();
             try {
                 mRootWindowContainer.getDefaultDisplay()
-                        .prepareAppTransition(
+                        .requestTransitionAndLegacyPrepare(
                                 isDisplayOccluded(DEFAULT_DISPLAY)
                                         ? TRANSIT_KEYGUARD_OCCLUDE
-                                        : TRANSIT_KEYGUARD_UNOCCLUDE);
+                                        : TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
                 // When the occluding activity also turns on the display, visibility of the activity
                 // can be committed before KEYGUARD_OCCLUDE transition is handled.
                 // Set mRequestForceTransition flag to make sure that the app transition animation
                 // is applied for such case.
-                if (topActivity != null) {
+                // TODO(b/194243906): Fix this before enabling the remote keyguard animation.
+                if (WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
+                        && topActivity != null) {
                     topActivity.mRequestForceTransition = true;
                 }
                 updateKeyguardSleepToken(DEFAULT_DISPLAY);
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index d230936..88941eb 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -138,7 +138,7 @@
         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
                 new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
                 mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
-                mWindowContainer.getWindowConfiguration(), true, null, null, null,
+                mWindowContainer.getWindowConfiguration(), true, null, null, null, false,
                 mWindowContainer.getWindowType());
         return mTarget;
     }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ede4c2e..dca0bbd 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1346,7 +1346,8 @@
                     + " activityType=" + task.getActivityType()
                     + " windowingMode=" + task.getWindowingMode()
                     + " isAlwaysOnTopWhenVisible=" + task.isAlwaysOnTopWhenVisible()
-                    + " intentFlags=" + task.getBaseIntent().getFlags());
+                    + " intentFlags=" + task.getBaseIntent().getFlags()
+                    + " isEmbedded=" + task.isEmbedded());
         }
 
         switch (task.getActivityType()) {
@@ -1392,6 +1393,11 @@
             return false;
         }
 
+        // Ignore the task if it is a embedded task
+        if (task.isEmbedded()) {
+            return false;
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e346e3e..c457df9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1102,6 +1102,23 @@
         return mTargetActivityRecord.findMainWindow();
     }
 
+    /**
+     * Returns the task with the highest layer, or null if none is found.
+     */
+    public Task getHighestLayerTask() {
+        int highestLayer = Integer.MIN_VALUE;
+        Task highestLayerTask = null;
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+            int layer = adapter.mTask.getPrefixOrderIndex();
+            if (layer > highestLayer) {
+                highestLayer = layer;
+                highestLayerTask = adapter.mTask;
+            }
+        }
+        return highestLayerTask;
+    }
+
     boolean isAnimatingTask(Task task) {
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             if (task == mPendingAnimations.get(i).mTask) {
@@ -1201,7 +1218,8 @@
                     !topApp.fillsParent(), new Rect(),
                     insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
                     mLocalBounds, mBounds, mTask.getWindowConfiguration(),
-                    mIsRecentTaskInvisible, null, null, mTask.getTaskInfo());
+                    mIsRecentTaskInvisible, null, null, mTask.getTaskInfo(),
+                    topApp.checkEnterPictureInPictureAppOpsState());
             return mTarget;
         }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 24c5c82..079868d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -365,8 +365,26 @@
                 return false;
             }
 
+            if (matchingCandidate(task)) {
+                return true;
+            }
+
+            // Looking for the embedded tasks (if any)
+            return !task.isLeafTaskFragment() && task.forAllLeafTaskFragments(
+                    this::matchingCandidate);
+        }
+
+        boolean matchingCandidate(TaskFragment taskFragment) {
+            final Task task = taskFragment.asTask();
+            if (task == null) {
+                return false;
+            }
+
             // Overlays should not be considered as the task's logical top activity.
-            final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
+            // Activities of the tasks that embedded from this one should not be used.
+            final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */,
+                    false /* includingEmbeddedTask */);
+
             if (r == null || r.finishing || r.mUserId != userId
                     || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                 ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
@@ -1980,7 +1998,8 @@
      */
     void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
             boolean preserveWindows, boolean notifyClients) {
-        if (mTaskSupervisor.inActivityVisibilityUpdate()) {
+        if (mTaskSupervisor.inActivityVisibilityUpdate()
+                || mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
             // Don't do recursive work.
             return;
         }
@@ -2811,7 +2830,6 @@
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
         r.detachFromProcess();
-        r.mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
         r.mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE,
                 TRANSIT_FLAG_APP_CRASHED);
         r.destroyIfPossible("handleAppCrashed");
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index c671e38..8b1befb 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -32,6 +32,12 @@
      */
     boolean mIsTransitionForward;
 
+    /**
+     * Non-null if the starting window should cover the bounds of associated task. It is assigned
+     * when the parent activity of starting window may be put in a partial area of the task.
+     */
+    Task mAssociatedTask;
+
     protected StartingData(WindowManagerService service, int typeParams) {
         mService = service;
         mTypeParams = typeParams;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 418be32..138117c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -125,7 +125,6 @@
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
 import static com.android.server.wm.TaskProto.TASK_FRAGMENT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
@@ -628,7 +627,7 @@
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
             boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
             boolean _removeWithTaskOrganizer) {
-        super(atmService, null /* fragmentToken */, _createdByOrganizer);
+        super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */);
 
         mTaskId = _taskId;
         mUserId = _userId;
@@ -707,13 +706,13 @@
         return this;
     }
 
-    private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) {
+    private void cleanUpResourcesForDestroy(WindowContainer<?> oldParent) {
         if (hasChild()) {
             return;
         }
 
         // This task is going away, so save the last state if necessary.
-        saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent());
+        saveLaunchingStateIfNeeded(oldParent.getDisplayContent());
 
         // TODO: VI what about activity?
         final boolean isVoiceSession = voiceSession != null;
@@ -1144,11 +1143,11 @@
     }
 
     @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final DisplayContent display = newParent != null
-                ? ((WindowContainer) newParent).getDisplayContent() : null;
-        final DisplayContent oldDisplay = oldParent != null
-                ? ((WindowContainer) oldParent).getDisplayContent() : null;
+    void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
+        final WindowContainer<?> newParent = (WindowContainer<?>) rawNewParent;
+        final WindowContainer<?> oldParent = (WindowContainer<?>) rawOldParent;
+        final DisplayContent display = newParent != null ? newParent.getDisplayContent() : null;
+        final DisplayContent oldDisplay = oldParent != null ? oldParent.getDisplayContent() : null;
 
         mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
 
@@ -1189,7 +1188,7 @@
         }
 
         if (oldParent != null) {
-            final Task oldParentTask = ((WindowContainer) oldParent).asTask();
+            final Task oldParentTask = oldParent.asTask();
             if (oldParentTask != null) {
                 final PooledConsumer c = PooledLambda.obtainConsumer(
                         Task::cleanUpActivityReferences, oldParentTask,
@@ -1394,14 +1393,6 @@
         return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
     }
 
-    ActivityRecord getTopNonFinishingActivity() {
-        return getTopNonFinishingActivity(true /* includeOverlays */);
-    }
-
-    ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
-        return getTopActivity(false /*includeFinishing*/, includeOverlays);
-    }
-
     ActivityRecord topRunningActivityLocked() {
         if (getParent() == null) {
             return null;
@@ -1521,7 +1512,7 @@
         if (DEBUG_TASK_MOVEMENT) {
             Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason);
         }
-        super.removeChild(r);
+        super.removeChild(r, false /* removeSelfIfPossible */);
 
         if (inPinnedWindowingMode()) {
             // We normally notify listeners of task stack changes on pause, however root pinned task
@@ -1551,7 +1542,10 @@
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
             // or created by task organizer.
             if (!isRootTask()) {
-                getRootTask().removeChild(this, reason);
+                final WindowContainer<?> parent = getParent();
+                if (parent != null) {
+                    parent.asTaskFragment().removeChild(this);
+                }
             }
             EventLogTags.writeWmTaskRemoved(mTaskId,
                     "removeChild:" + reason + " last r=" + r + " in t=" + this);
@@ -2602,25 +2596,12 @@
         }
     }
 
-    @VisibleForTesting
-    boolean hasWindowsAlive() {
-        return getActivity(ActivityRecord::hasWindowsAlive) != null;
-    }
-
-    @VisibleForTesting
-    boolean shouldDeferRemoval() {
-        if (mChildren.isEmpty()) {
-            // No reason to defer removal of a Task that doesn't have any child.
-            return false;
-        }
-        return hasWindowsAlive() && getRootTask().isAnimating(TRANSITION | CHILDREN);
-    }
-
     @Override
     void removeImmediately() {
         removeImmediately("removeTask");
     }
 
+    @Override
     void removeImmediately(String reason) {
         if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId);
         if (mRemoving) {
@@ -2976,11 +2957,54 @@
     /** Returns the top-most activity that occludes the given one, or {@code null} if none. */
     @Nullable
     ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
-        final ActivityRecord top = getActivity(ActivityRecord::occludesParent,
-                true /* traverseTopToBottom */, activity);
+        final ActivityRecord top = getActivity(r -> {
+            if (r == activity) {
+                // Reached the given activity, return the activity to stop searching.
+                return true;
+            }
+
+            if (!r.occludesParent()) {
+                return false;
+            }
+
+            TaskFragment parent = r.getTaskFragment();
+            if (parent == activity.getTaskFragment()) {
+                // Found it. This activity on top of the given activity on the same TaskFragment.
+                return true;
+            }
+            if (isSelfOrNonEmbeddedTask(parent.asTask())) {
+                // Found it. This activity is the direct child of a leaf Task without being
+                // embedded.
+                return true;
+            }
+            // The candidate activity is being embedded. Checking if the bounds of the containing
+            // TaskFragment equals to the outer TaskFragment.
+            TaskFragment grandParent = parent.getParent().asTaskFragment();
+            while (grandParent != null) {
+                if (!parent.getBounds().equals(grandParent.getBounds())) {
+                    // Not occluding the grandparent.
+                    break;
+                }
+                if (isSelfOrNonEmbeddedTask(grandParent.asTask())) {
+                    // Found it. The activity occludes its parent TaskFragment and the parent
+                    // TaskFragment also occludes its parent all the way up.
+                    return true;
+                }
+                parent = grandParent;
+                grandParent = parent.getParent().asTaskFragment();
+            }
+            return false;
+        });
         return top != activity ? top : null;
     }
 
+    private boolean isSelfOrNonEmbeddedTask(Task task) {
+        if (task == this) {
+            return true;
+        }
+        return task != null && !task.isEmbedded();
+    }
+
     @Override
     public SurfaceControl.Builder makeAnimationLeash() {
         return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
@@ -3217,7 +3241,7 @@
             boolean consumed = false;
             if (traverseTopToBottom) {
                 for (int i = task.mChildren.size() - 1; i >= 0; --i) {
-                    final WindowContainer child = mChildren.get(i);
+                    final WindowContainer child = task.mChildren.get(i);
                     if (child.asTaskFragment() != null) {
                         child.forAllLeafTaskFragments(callback, traverseTopToBottom);
                     } else if (child.asActivityRecord() != null && !consumed) {
@@ -3227,7 +3251,7 @@
                 }
             } else {
                 for (int i = 0; i < task.mChildren.size(); i++) {
-                    final WindowContainer child = mChildren.get(i);
+                    final WindowContainer child = task.mChildren.get(i);
                     if (child.asTaskFragment() != null) {
                         child.forAllLeafTaskFragments(callback, traverseTopToBottom);
                     } else if (child.asActivityRecord() != null && !consumed) {
@@ -3358,19 +3382,9 @@
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
-        pw.println(prefix + "bounds=" + getBounds().toShortString());
-        final String doublePrefix = prefix + "  ";
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowContainer<?> child = mChildren.get(i);
-            pw.println(prefix + "* " + child);
-            // Only dump non-activity because full activity info is already printed by
-            // RootWindowContainer#dumpActivities.
-            if (child.asActivityRecord() == null) {
-                child.dump(pw, doublePrefix, dumpAll);
-            }
-        }
 
         if (!mExitingActivities.isEmpty()) {
+            final String doublePrefix = prefix + "  ";
             pw.println();
             pw.println(prefix + "Exiting application tokens:");
             for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
@@ -4139,8 +4153,7 @@
     }
 
     private boolean canBeOrganized() {
-        if (mForceNotOrganized || !mAtmService.mTaskOrganizerController
-                .isSupportedWindowingMode(getWindowingMode())) {
+        if (mForceNotOrganized) {
             return false;
         }
         // All root tasks can be organized
@@ -4297,7 +4310,7 @@
 
         final int windowingMode = getWindowingMode();
         final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController;
-        final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
+        final ITaskOrganizer organizer = controller.getTaskOrganizer();
         if (!forceUpdate && mTaskOrganizer == organizer) {
             return false;
         }
@@ -4316,10 +4329,10 @@
      * @return true if the task is currently focused.
      */
     private boolean isFocused() {
-        if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
+        if (mDisplayContent == null || mDisplayContent.mFocusedApp == null) {
             return false;
         }
-        return mDisplayContent.mCurrentFocus.getTask() == this;
+        return mDisplayContent.mFocusedApp.getTask() == this;
     }
 
     /**
@@ -4376,10 +4389,9 @@
      * Called on the task of a window which gained or lost focus.
      * @param hasFocus
      */
-    void onWindowFocusChanged(boolean hasFocus) {
+    void onAppFocusChanged(boolean hasFocus) {
         updateShadowsRadius(hasFocus, getSyncTransaction());
-        // TODO(b/180525887): Un-comment once there is resolution on the bug.
-        // dispatchTaskInfoChangedIfNeeded(false /* force */);
+        dispatchTaskInfoChangedIfNeeded(false /* force */);
     }
 
     void onPictureInPictureParamsChanged() {
@@ -4632,8 +4644,10 @@
             mAtmService.continueWindowLayout();
         }
 
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
-        mRootWindowContainer.resumeFocusedTasksTopActivities();
+        if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
+            mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            mRootWindowContainer.resumeFocusedTasksTopActivities();
+        }
     }
 
     void resumeNextFocusAfterReparent() {
@@ -5059,7 +5073,7 @@
     }
 
     void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
-            boolean newTask, boolean keepCurTransition, ActivityOptions options,
+            boolean newTask, boolean isTaskSwitch, ActivityOptions options,
             @Nullable ActivityRecord sourceRecord) {
         Task rTask = r.getTask();
         final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
@@ -5165,22 +5179,18 @@
                 // "has the same starting icon" as the next one.  This allows the
                 // window manager to keep the previous window it had previously
                 // created, if it still had one.
-                Task prevTask = r.getTask();
-                ActivityRecord prev = prevTask.getActivity(
-                        a -> a.mStartingData != null && a.okToShowLocked());
-                if (prev != null) {
-                    // We don't want to reuse the previous starting preview if:
-                    // (1) The current activity is in a different task.
-                    if (prev.getTask() != prevTask) {
-                        prev = null;
-                    }
-                    // (2) The current activity is already displayed.
-                    else if (prev.nowVisible) {
-                        prev = null;
-                    }
+                Task baseTask = r.getTask();
+                if (baseTask.isEmbedded()) {
+                    // If the task is embedded in a task fragment, there may have an existing
+                    // starting window in the parent task. This allows the embedded activities
+                    // to share the starting window and make sure that the window can have top
+                    // z-order by transferring to the top activity.
+                    baseTask = baseTask.getParent().asTaskFragment().getTask();
                 }
 
-                r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity),
+                final ActivityRecord prev = baseTask.getActivity(
+                        a -> a.mStartingData != null && a.okToShowLocked());
+                r.showStartingWindow(prev, newTask, isTaskSwitch,
                         true /* startActivity */, sourceRecord);
             }
         } else {
@@ -5214,10 +5224,6 @@
         return true;
     }
 
-    private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) {
-        return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
-    }
-
     /**
      * Reset the task by reparenting the activities that have same affinity to the task or
      * reparenting the activities that have different affinityies out of the task, while these
@@ -5275,7 +5281,6 @@
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
         Task finishedTask = r.getTask();
-        mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
         mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
         r.finishIfPossible(reason, false /* oomAdj */);
 
@@ -5333,18 +5338,6 @@
         return true;
     }
 
-    /** Finish all activities in the root task without waiting. */
-    void finishAllActivitiesImmediately() {
-        if (!hasChild()) {
-            removeIfPossible("finishAllActivitiesImmediately");
-            return;
-        }
-        forAllActivities((r) -> {
-            Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
-            r.destroyIfPossible("finishAllActivitiesImmediately");
-        });
-    }
-
     /** @return true if the root task behind this one is a standard activity type. */
     private boolean inFrontOfStandardRootTask() {
         final TaskDisplayArea taskDisplayArea = getDisplayArea();
@@ -5655,7 +5648,6 @@
 
         // Skip the transition for pinned task.
         if (!inPinnedWindowingMode()) {
-            mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK);
             mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr);
         }
         moveToBack("moveTaskToBackLocked", tr);
@@ -5741,17 +5733,14 @@
 
     @Override
     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
-        pw.print(prefix); pw.print("* "); pw.println(this);
-        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
-        pw.println(prefix + "  mCreatedByOrganizer=" + mCreatedByOrganizer);
+        super.dumpInner(prefix, pw, dumpAll, dumpPackage);
+        if (mCreatedByOrganizer) {
+            pw.println(prefix + "  mCreatedByOrganizer=true");
+        }
         if (mLastNonFullscreenBounds != null) {
             pw.print(prefix); pw.print("  mLastNonFullscreenBounds=");
             pw.println(mLastNonFullscreenBounds);
         }
-        if (dumpAll) {
-            printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
-                    prefix + "  mLastPausedActivity: ", null);
-        }
         if (isLeafTask()) {
             pw.println(prefix + "  isSleeping=" + shouldSleepActivities());
             printThisActivity(pw, getTopPausingActivity(), dumpPackage, false,
@@ -6148,16 +6137,6 @@
         getDisplayContent().getPinnedTaskController().setActions(actions);
     }
 
-    /** Returns true if a removal action is still being deferred. */
-    boolean handleCompleteDeferredRemoval() {
-        if (isAnimating(TRANSITION | CHILDREN)
-                || mAtmService.getTransitionController().inTransition(this)) {
-            return true;
-        }
-
-        return super.handleCompleteDeferredRemoval();
-    }
-
     public DisplayInfo getDisplayInfo() {
         return mDisplayContent.getDisplayInfo();
     }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 10c16ff..cfad936 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -780,10 +780,12 @@
             }
             return SCREEN_ORIENTATION_UNSPECIFIED;
         } else {
-            // Apps and their containers are not allowed to specify an orientation of full screen
-            // tasks created by organizer. The organizer handles the orientation instead.
-            final Task task = getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            if (task != null && task.isVisible() && task.mCreatedByOrganizer) {
+            // Apps and their containers are not allowed to specify an orientation of non floating
+            // visible tasks created by organizer. The organizer handles the orientation instead.
+            final Task nonFloatingTopTask =
+                    getRootTask(t -> !t.getWindowConfiguration().tasksAreFloating());
+            if (nonFloatingTopTask != null && nonFloatingTopTask.mCreatedByOrganizer
+                    && nonFloatingTopTask.isVisible()) {
                 return SCREEN_ORIENTATION_UNSPECIFIED;
             }
         }
@@ -2102,7 +2104,7 @@
             if (destroyContentOnRemoval
                     || !task.isActivityTypeStandardOrUndefined()
                     || task.mCreatedByOrganizer) {
-                task.finishAllActivitiesImmediately();
+                task.remove(false /* withTransition */, "removeTaskDisplayArea");
             } else {
                 // Reparent task to corresponding launch root or display area.
                 final WindowContainer launchRoot =
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1eec6aa..6c31716 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -61,6 +61,8 @@
 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
 
 import android.annotation.IntDef;
@@ -158,10 +160,11 @@
      */
     int mMinHeight;
 
-    /** Avoid reentrant of {@link #removeImmediately()}. */
-    private boolean mRemoving;
+    /** This task fragment will be removed when the cleanup of its children are done. */
+    private boolean mIsRemovalRequested;
 
-    // The TaskFragment that adjacent to this one.
+    /** The TaskFragment that is adjacent to this one. */
+    @Nullable
     private TaskFragment mAdjacentTaskFragment;
 
     /**
@@ -206,6 +209,9 @@
     @VisibleForTesting
     boolean mCreatedByOrganizer;
 
+    /** Whether this TaskFragment is embedded in a task. */
+    private final boolean mIsEmbedded;
+
     /** Organizer that organizing this TaskFragment. */
     @Nullable
     private ITaskFragmentOrganizer mTaskFragmentOrganizer;
@@ -268,23 +274,51 @@
         }
     }
 
+    /** Creates an embedded task fragment. */
     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
             boolean createdByOrganizer) {
+        this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */);
+    }
+
+    TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
+            boolean createdByOrganizer, boolean isEmbedded) {
         super(atmService.mWindowManager);
 
         mAtmService = atmService;
         mTaskSupervisor = mAtmService.mTaskSupervisor;
         mRootWindowContainer = mAtmService.mRootWindowContainer;
         mCreatedByOrganizer = createdByOrganizer;
+        mIsEmbedded = isEmbedded;
         mTaskFragmentOrganizerController =
                 mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
         mFragmentToken = fragmentToken;
         mRemoteToken = new RemoteToken(this);
     }
 
-    void setAdjacentTaskFragment(TaskFragment taskFragment) {
-        mAdjacentTaskFragment = taskFragment;
-        taskFragment.mAdjacentTaskFragment = this;
+    @NonNull
+    static TaskFragment fromTaskFragmentToken(@Nullable IBinder token,
+            @NonNull ActivityTaskManagerService service) {
+        if (token == null) return null;
+        return service.mWindowOrganizerController.getTaskFragment(token);
+    }
+
+    void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
+        if (mAdjacentTaskFragment == taskFragment) {
+            return;
+        }
+        resetAdjacentTaskFragment();
+        if (taskFragment != null) {
+            mAdjacentTaskFragment = taskFragment;
+            taskFragment.setAdjacentTaskFragment(this);
+        }
+    }
+
+    private void resetAdjacentTaskFragment() {
+        // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
+        if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
+            mAdjacentTaskFragment.mAdjacentTaskFragment = null;
+        }
+        mAdjacentTaskFragment = null;
     }
 
     void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
@@ -374,6 +408,18 @@
         return this;
     }
 
+    /** Returns {@code true} if this is a container for embedded activities or tasks. */
+    boolean isEmbedded() {
+        if (mIsEmbedded) {
+            return true;
+        }
+        final WindowContainer<?> parent = getParent();
+        if (parent != null) {
+            final TaskFragment taskFragment = parent.asTaskFragment();
+            return taskFragment != null && taskFragment.isEmbedded();
+        }
+        return false;
+    }
 
     /**
      * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
@@ -570,17 +616,68 @@
         return false;
     }
 
+    ActivityRecord getTopNonFinishingActivity() {
+        return getTopNonFinishingActivity(true /* includeOverlays */);
+    }
+
+    ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
+        return getTopNonFinishingActivity(includeOverlays, true /* includingEmbeddedTask */);
+    }
+
+    /**
+     * Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
+     * the current user.
+     * @param includeOverlays whether the task overlay activity should be included.
+     * @param includingEmbeddedTask whether the activity in a task that being embedded from this
+     *                              one should be included.
+     * @see #topRunningActivity(boolean, boolean)
+     * @see ActivityRecord#okToShowLocked()
+     */
+    ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
+            boolean includingEmbeddedTask) {
+        // Split into 4 to avoid object creation due to variable capture.
+        if (includeOverlays) {
+            if (includingEmbeddedTask) {
+                return getActivity((r) -> !r.finishing);
+            }
+            return getActivity((r) -> !r.finishing && r.getTask() == this.getTask());
+        }
+
+        if (includingEmbeddedTask) {
+            return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
+        }
+        return getActivity(
+                (r) -> !r.finishing && !r.isTaskOverlay() && r.getTask() == this.getTask());
+    }
+
     ActivityRecord topRunningActivity() {
         return topRunningActivity(false /* focusableOnly */);
     }
 
     ActivityRecord topRunningActivity(boolean focusableOnly) {
-        // Split into 2 to avoid object creation due to variable capture.
+        return topRunningActivity(focusableOnly, true /* includingEmbeddedTask */);
+    }
+
+    /**
+     * Returns the top-most running activity, which the activity is non-finishing and ok to show
+     * to the current user.
+     *
+     * @see ActivityRecord#canBeTopRunning()
+     */
+    ActivityRecord topRunningActivity(boolean focusableOnly, boolean includingEmbeddedTask) {
+        // Split into 4 to avoid object creation due to variable capture.
         if (focusableOnly) {
-            return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
-        } else {
+            if (includingEmbeddedTask) {
+                return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
+            }
+            return getActivity(
+                    (r) -> r.canBeTopRunning() && r.isFocusable() && r.getTask() == this.getTask());
+        }
+
+        if (includingEmbeddedTask) {
             return getActivity(ActivityRecord::canBeTopRunning);
         }
+        return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
     }
 
     boolean isTopActivityFocusable() {
@@ -1303,6 +1400,8 @@
 
             } else {
                 prev.schedulePauseTimeout();
+                // Unset readiness since we now need to wait until this pause is complete.
+                mAtmService.getTransitionController().setReady(this, false /* ready */);
                 return true;
             }
 
@@ -1887,6 +1986,10 @@
         }
     }
 
+    int getTaskFragmentOrganizerPid() {
+        return mTaskFragmentOrganizerPid;
+    }
+
     /**
      * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
      * called from {@link Task}.
@@ -1946,14 +2049,67 @@
     }
 
     @Override
-    void removeImmediately() {
-        if (mRemoving) {
+    void removeChild(WindowContainer child) {
+        removeChild(child, true /* removeSelfIfPossible */);
+    }
+
+    void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
+        super.removeChild(child);
+        if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
+            removeImmediately("removeLastChild " + child);
+        }
+    }
+
+    /**
+     * Requests to remove this task fragment. If it doesn't have children, it is removed
+     * immediately. Otherwise it will be removed until all activities are destroyed.
+     *
+     * @param withTransition Whether to use transition animation when removing activities. Set to
+     *                       {@code false} if this is invisible to user, e.g. display removal.
+     */
+    void remove(boolean withTransition, String reason) {
+        if (!hasChild()) {
+            removeImmediately(reason);
             return;
         }
-        mRemoving = true;
+        mIsRemovalRequested = true;
+        forAllActivities(r -> {
+            if (withTransition) {
+                r.finishIfPossible(reason, false /* oomAdj */);
+            } else {
+                r.destroyIfPossible(reason);
+            }
+        });
+    }
+
+    boolean shouldDeferRemoval() {
+        if (!hasChild()) {
+            return false;
+        }
+        return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
+                || mAtmService.getTransitionController().inTransition(this);
+    }
+
+    @Override
+    boolean handleCompleteDeferredRemoval() {
+        if (shouldDeferRemoval()) {
+            return true;
+        }
+        return super.handleCompleteDeferredRemoval();
+    }
+
+    /** The overridden method must call {@link #removeImmediately()} instead of super. */
+    void removeImmediately(String reason) {
+        Slog.d(TAG, "Remove task fragment: " + reason);
+        removeImmediately();
+    }
+
+    @Override
+    void removeImmediately() {
+        mIsRemovalRequested = false;
+        resetAdjacentTaskFragment();
         super.removeImmediately();
         sendTaskFragmentVanished();
-        mRemoving = false;
     }
 
     boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
@@ -1981,10 +2137,10 @@
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             WindowContainer child = mChildren.get(i);
             if (child.asTaskFragment() != null) {
-                printed |= child.asTaskFragment().dump(prefix + "      ", fd, pw, dumpAll,
+                printed |= child.asTaskFragment().dump(prefix + "  ", fd, pw, dumpAll,
                         dumpClient, dumpPackage, needSep, headerPrinter);
             } else if (child.asActivityRecord() != null) {
-                ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "      ",
+                ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "  ",
                         "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
                         getTask());
             }
@@ -1995,7 +2151,13 @@
 
     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
         pw.print(prefix); pw.print("* "); pw.println(this);
-        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
+        final Rect bounds = getRequestedOverrideBounds();
+        if (!bounds.isEmpty()) {
+            pw.println(prefix + "  mBounds=" + bounds);
+        }
+        if (mIsRemovalRequested) {
+            pw.println(prefix + "  mIsRemovalRequested=true");
+        }
         if (dumpAll) {
             printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
                     prefix + "  mLastPausedActivity: ", null);
@@ -2003,6 +2165,22 @@
     }
 
     @Override
+    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        super.dump(pw, prefix, dumpAll);
+        pw.println(prefix + "bounds=" + getBounds().toShortString());
+        final String doublePrefix = prefix + "  ";
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowContainer<?> child = mChildren.get(i);
+            pw.println(prefix + "* " + child);
+            // Only dump non-activity because full activity info is already printed by
+            // RootWindowContainer#dumpActivities.
+            if (child.asActivityRecord() == null) {
+                child.dump(pw, doublePrefix, dumpAll);
+            }
+        }
+    }
+
+    @Override
     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 4843e5a..96860a2 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -116,8 +116,11 @@
         }
 
         void dispose() {
-            mOrganizedTaskFragments.forEach(TaskFragment::removeImmediately);
-            mOrganizedTaskFragments.clear();
+            while (!mOrganizedTaskFragments.isEmpty()) {
+                final TaskFragment taskFragment = mOrganizedTaskFragments.get(0);
+                taskFragment.removeImmediately();
+                mOrganizedTaskFragments.remove(taskFragment);
+            }
             mOrganizer.asBinder().unlinkToDeath(this, 0 /*flags*/);
         }
 
@@ -227,11 +230,16 @@
         validateAndGetState(organizer);
         final int pid = Binder.getCallingPid();
         final long uid = Binder.getCallingUid();
-        synchronized (mGlobalLock) {
-            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
-                    "Unregister task fragment organizer=%s uid=%d pid=%d",
-                    organizer.asBinder(), uid, pid);
-            removeOrganizer(organizer);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                        "Unregister task fragment organizer=%s uid=%d pid=%d",
+                        organizer.asBinder(), uid, pid);
+                removeOrganizer(organizer);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9ca89cb..fa7b276 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
@@ -67,14 +64,6 @@
 class TaskOrganizerController extends ITaskOrganizerController.Stub {
     private static final String TAG = "TaskOrganizerController";
 
-    // The set of modes that are currently supports
-    // TODO: Remove once the task organizer can support all modes
-    @VisibleForTesting
-    static final int[] UNSUPPORTED_WINDOWING_MODES = {
-            WINDOWING_MODE_UNDEFINED,
-            WINDOWING_MODE_FREEFORM
-    };
-
     private class DeathRecipient implements IBinder.DeathRecipient {
         ITaskOrganizer mTaskOrganizer;
 
@@ -113,109 +102,6 @@
             return mTaskOrganizer.asBinder();
         }
 
-        void addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
-                TaskSnapshot taskSnapshot) {
-            final StartingWindowInfo info = task.getStartingWindowInfo(activity);
-            if (launchTheme != 0) {
-                info.splashScreenThemeResId = launchTheme;
-            }
-            info.mTaskSnapshot = taskSnapshot;
-            // make this happen prior than prepare surface
-            try {
-                mTaskOrganizer.addStartingWindow(info, activity.token);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskStart callback", e);
-            }
-        }
-
-        // Capture the animation surface control for activity's main window
-        private class StartingWindowAnimationAdaptor implements AnimationAdapter {
-            private SurfaceControl mAnimationLeash;
-            @Override
-            public boolean getShowWallpaper() {
-                return false;
-            }
-
-            @Override
-            public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
-                    int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
-                mAnimationLeash = animationLeash;
-            }
-
-            @Override
-            public void onAnimationCancelled(SurfaceControl animationLeash) {
-                if (mAnimationLeash == animationLeash) {
-                    mAnimationLeash = null;
-                }
-            }
-
-            @Override
-            public long getDurationHint() {
-                return 0;
-            }
-
-            @Override
-            public long getStatusBarTransitionsStartTime() {
-                return 0;
-            }
-
-            @Override
-            public void dump(PrintWriter pw, String prefix) {
-                pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash=");
-                pw.print(mAnimationLeash);
-                pw.println();
-            }
-
-            @Override
-            public void dumpDebug(ProtoOutputStream proto) {
-            }
-        }
-
-        void removeStartingWindow(Task task, boolean prepareAnimation) {
-            SurfaceControl windowAnimationLeash = null;
-            Rect mainFrame = null;
-            final boolean playShiftUpAnimation = !task.inMultiWindowMode();
-            if (prepareAnimation && playShiftUpAnimation) {
-                final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
-                if (topActivity != null) {
-                    final WindowState mainWindow =
-                            topActivity.findMainWindow(false/* includeStartingApp */);
-                    if (mainWindow != null) {
-                        final StartingWindowAnimationAdaptor adaptor =
-                                new StartingWindowAnimationAdaptor();
-                        final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
-                        mainWindow.startAnimation(t, adaptor, false,
-                                ANIMATION_TYPE_STARTING_REVEAL);
-                        windowAnimationLeash = adaptor.mAnimationLeash;
-                        mainFrame = mainWindow.getRelativeFrame();
-                        t.setPosition(windowAnimationLeash, mainFrame.left, mainFrame.top);
-                    }
-                }
-            }
-            try {
-                mTaskOrganizer.removeStartingWindow(task.mTaskId, windowAnimationLeash,
-                        mainFrame, prepareAnimation);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
-            }
-        }
-
-        void copySplashScreenView(Task task) {
-            try {
-                mTaskOrganizer.copySplashScreenView(task.mTaskId);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending copyStartingWindowView callback", e);
-            }
-        }
-
-        void onAppSplashScreenViewRemoved(Task task) {
-            try {
-                mTaskOrganizer.onAppSplashScreenViewRemoved(task.mTaskId);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e);
-            }
-        }
-
         SurfaceControl prepareLeash(Task task, String reason) {
             return new SurfaceControl(task.getSurfaceControl(), reason);
         }
@@ -302,23 +188,6 @@
             mUid = uid;
         }
 
-        void addStartingWindow(Task t, ActivityRecord activity, int launchTheme,
-                TaskSnapshot taskSnapshot) {
-            mOrganizer.addStartingWindow(t, activity, launchTheme, taskSnapshot);
-        }
-
-        void removeStartingWindow(Task t, boolean prepareAnimation) {
-            mOrganizer.removeStartingWindow(t, prepareAnimation);
-        }
-
-        void copySplashScreenView(Task t) {
-            mOrganizer.copySplashScreenView(t);
-        }
-
-        public void onAppSplashScreenViewRemoved(Task t) {
-            mOrganizer.onAppSplashScreenViewRemoved(t);
-        }
-
         /**
          * Register this task with this state, but doesn't trigger the task appeared callback to
          * the organizer.
@@ -493,11 +362,6 @@
 
                 final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
                 mService.mRootWindowContainer.forAllTasks((task) -> {
-                    if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES,
-                            task.getWindowingMode())) {
-                        return;
-                    }
-
                     boolean returnTask = !task.mCreatedByOrganizer;
                     task.updateTaskOrganizerState(true /* forceUpdate */,
                             returnTask /* skipTaskAppeared */);
@@ -553,46 +417,130 @@
     /**
      * @return the task organizer key for a given windowing mode.
      */
-    ITaskOrganizer getTaskOrganizer(int windowingMode) {
-        return isSupportedWindowingMode(windowingMode)
-                ? mTaskOrganizers.peekLast()
-                : null;
+    ITaskOrganizer getTaskOrganizer() {
+        return mTaskOrganizers.peekLast();
     }
 
-    boolean isSupportedWindowingMode(int winMode) {
-        return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
+    // Capture the animation surface control for activity's main window
+    private static class StartingWindowAnimationAdaptor implements AnimationAdapter {
+        private SurfaceControl mAnimationLeash;
+        @Override
+        public boolean getShowWallpaper() {
+            return false;
+        }
+
+        @Override
+        public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
+                int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+            mAnimationLeash = animationLeash;
+        }
+
+        @Override
+        public void onAnimationCancelled(SurfaceControl animationLeash) {
+            if (mAnimationLeash == animationLeash) {
+                mAnimationLeash = null;
+            }
+        }
+
+        @Override
+        public long getDurationHint() {
+            return 0;
+        }
+
+        @Override
+        public long getStatusBarTransitionsStartTime() {
+            return 0;
+        }
+
+        @Override
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash=");
+            pw.print(mAnimationLeash);
+            pw.println();
+        }
+
+        @Override
+        public void dumpDebug(ProtoOutputStream proto) {
+        }
     }
 
     boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
             TaskSnapshot taskSnapshot) {
         final Task rootTask = task.getRootTask();
-        if (rootTask == null || rootTask.mTaskOrganizer == null || activity.mStartingData == null) {
+        if (rootTask == null || activity.mStartingData == null) {
             return false;
         }
-        final TaskOrganizerState state =
-                mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
-        state.addStartingWindow(task, activity, launchTheme, taskSnapshot);
+        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        if (lastOrganizer == null) {
+            return false;
+        }
+        final StartingWindowInfo info = task.getStartingWindowInfo(activity);
+        if (launchTheme != 0) {
+            info.splashScreenThemeResId = launchTheme;
+        }
+        info.mTaskSnapshot = taskSnapshot;
+        // make this happen prior than prepare surface
+        try {
+            lastOrganizer.addStartingWindow(info, activity.token);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Exception sending onTaskStart callback", e);
+            return false;
+        }
         return true;
     }
 
     void removeStartingWindow(Task task, boolean prepareAnimation) {
         final Task rootTask = task.getRootTask();
-        if (rootTask == null || rootTask.mTaskOrganizer == null) {
+        if (rootTask == null) {
             return;
         }
-        final TaskOrganizerState state =
-                mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
-        state.removeStartingWindow(task, prepareAnimation);
+        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        if (lastOrganizer == null) {
+            return;
+        }
+        SurfaceControl windowAnimationLeash = null;
+        Rect mainFrame = null;
+        final boolean playShiftUpAnimation = !task.inMultiWindowMode();
+        if (prepareAnimation && playShiftUpAnimation) {
+            final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
+            if (topActivity != null) {
+                final WindowState mainWindow =
+                        topActivity.findMainWindow(false/* includeStartingApp */);
+                if (mainWindow != null) {
+                    final StartingWindowAnimationAdaptor adaptor =
+                            new StartingWindowAnimationAdaptor();
+                    final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
+                    mainWindow.startAnimation(t, adaptor, false,
+                            ANIMATION_TYPE_STARTING_REVEAL);
+                    windowAnimationLeash = adaptor.mAnimationLeash;
+                    mainFrame = mainWindow.getRelativeFrame();
+                    t.setPosition(windowAnimationLeash, mainFrame.left, mainFrame.top);
+                }
+            }
+        }
+        try {
+            lastOrganizer.removeStartingWindow(task.mTaskId, windowAnimationLeash,
+                    mainFrame, prepareAnimation);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
+        }
     }
 
     boolean copySplashScreenView(Task task) {
         final Task rootTask = task.getRootTask();
-        if (rootTask == null || rootTask.mTaskOrganizer == null) {
+        if (rootTask == null) {
             return false;
         }
-        final TaskOrganizerState state =
-                mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
-        state.copySplashScreenView(task);
+        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        if (lastOrganizer == null) {
+            return false;
+        }
+        try {
+            lastOrganizer.copySplashScreenView(task.mTaskId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Exception sending copyStartingWindowView callback", e);
+            return false;
+        }
         return true;
     }
 
@@ -604,12 +552,18 @@
      */
     public void onAppSplashScreenViewRemoved(Task task) {
         final Task rootTask = task.getRootTask();
-        if (rootTask == null || rootTask.mTaskOrganizer == null) {
+        if (rootTask == null) {
             return;
         }
-        final TaskOrganizerState state =
-                mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
-        state.onAppSplashScreenViewRemoved(task);
+        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        if (lastOrganizer == null) {
+            return;
+        }
+        try {
+            lastOrganizer.onAppSplashScreenViewRemoved(task.mTaskId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e);
+        }
     }
 
     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -704,7 +658,7 @@
 
                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
                         task.getDisplayId(), task.getWindowingMode());
-                task.removeImmediately("deleteRootTask");
+                task.remove(true /* withTransition */, "deleteRootTask");
                 return true;
             }
         } finally {
@@ -1017,9 +971,6 @@
             for (int k = 0; k < tasks.size(); k++) {
                 final Task task = tasks.get(k);
                 final int mode = task.getWindowingMode();
-                if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, mode)) {
-                    continue;
-                }
                 pw.println(innerPrefix + "    ("
                         + WindowConfiguration.windowingModeToString(mode) + ") " + task);
             }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index c85615d..54390dc 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -114,14 +114,9 @@
     private final boolean mIsRunningOnIoT;
 
     /**
-     * Flag indicating whether we are running on an Android Wear device.
+     * Flag indicating if task snapshot is enabled on this device.
      */
-    private final boolean mIsRunningOnWear;
-
-    /**
-     * Flag indicating if device configuration has disabled app snapshots.
-     */
-    private final boolean mConfigDisableTaskSnapshots;
+    private boolean mTaskSnapshotEnabled;
 
     TaskSnapshotController(WindowManagerService service) {
         mService = service;
@@ -132,12 +127,12 @@
                 PackageManager.FEATURE_LEANBACK);
         mIsRunningOnIoT = mService.mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_EMBEDDED);
-        mIsRunningOnWear = mService.mContext.getPackageManager().hasSystemFeature(
-            PackageManager.FEATURE_WATCH);
         mHighResTaskSnapshotScale = mService.mContext.getResources().getFloat(
                 com.android.internal.R.dimen.config_highResTaskSnapshotScale);
-        mConfigDisableTaskSnapshots = mService.mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_disableTaskSnapshots);
+        mTaskSnapshotEnabled =
+                !mService.mContext
+                        .getResources()
+                        .getBoolean(com.android.internal.R.bool.config_disableTaskSnapshots);
     }
 
     void systemReady() {
@@ -494,9 +489,12 @@
         return builder.build();
     }
 
+    void setTaskSnapshotEnabled(boolean enabled) {
+        mTaskSnapshotEnabled = enabled;
+    }
+
     boolean shouldDisableSnapshots() {
-        return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT
-                || mConfigDisableTaskSnapshots;
+        return mIsRunningOnTv || mIsRunningOnIoT || !mTaskSnapshotEnabled;
     }
 
     /**
@@ -696,6 +694,7 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "mHighResTaskSnapshotScale=" + mHighResTaskSnapshotScale);
+        pw.println(prefix + "mTaskSnapshotEnabled=" + mTaskSnapshotEnabled);
         mCache.dump(pw, prefix);
     }
 }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 2c17b73..5366bd4 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -20,6 +20,8 @@
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -33,10 +35,14 @@
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.TransitionFlags;
+import static android.view.WindowManager.TransitionType;
 import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -59,7 +65,6 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.view.SurfaceControl;
-import android.view.WindowManager;
 import android.view.animation.Animation;
 import android.window.IRemoteTransition;
 import android.window.TransitionInfo;
@@ -109,9 +114,9 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionState {}
 
-    final @WindowManager.TransitionType int mType;
+    final @TransitionType int mType;
     private int mSyncId;
-    private @WindowManager.TransitionFlags int mFlags;
+    private @TransitionFlags int mFlags;
     private final TransitionController mController;
     private final BLASTSyncEngine mSyncEngine;
     private IRemoteTransition mRemoteTransition = null;
@@ -146,7 +151,7 @@
     private boolean mNavBarAttachedToApp = false;
     private int mNavBarDisplayId = INVALID_DISPLAY;
 
-    Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags,
+    Transition(@TransitionType int type, @TransitionFlags int flags,
             TransitionController controller, BLASTSyncEngine syncEngine) {
         mType = type;
         mFlags = flags;
@@ -617,7 +622,7 @@
     }
 
     private void handleNonAppWindowsInTransition(int displayId,
-            @WindowManager.TransitionType int transit, int flags) {
+            @TransitionType int transit, int flags) {
         final DisplayContent dc =
                 mController.mAtm.mRootWindowContainer.getDisplayContent(displayId);
         if (dc == null) {
@@ -655,7 +660,7 @@
         ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
         for (int i = mParticipants.size() - 1; i >= 0; --i) {
             ActivityRecord r = mParticipants.valueAt(i).asActivityRecord();
-            if (r == null) continue;
+            if (r == null || !r.mVisibleRequested) continue;
             // At this point, r is "ready", but if it's not "ALL ready" then it is probably only
             // ready due to starting-window.
             reasons.put(r, (r.mStartingData instanceof SplashScreenStartingData
@@ -704,6 +709,22 @@
         return wc.asWallpaperToken() != null;
     }
 
+    private static boolean occludesKeyguard(WindowContainer wc) {
+        final ActivityRecord ar = wc.asActivityRecord();
+        if (ar != null) {
+            return ar.canShowWhenLocked();
+        }
+        final Task t = wc.asTask();
+        if (t != null) {
+            // Get the top activity which was visible (since this is going away, it will remain
+            // client visible until the transition is finished).
+            // skip hidden (or about to hide) apps
+            final ActivityRecord top = t.getActivity(WindowToken::isClientVisible);
+            return top != null && top.canShowWhenLocked();
+        }
+        return false;
+    }
+
     /**
      * Under some conditions (eg. all visible targets within a parent container are transitioning
      * the same way) the transition can be "promoted" to the parent container. This means an
@@ -968,7 +989,7 @@
      */
     @VisibleForTesting
     @NonNull
-    static TransitionInfo calculateTransitionInfo(int type, int flags,
+    static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
             ArraySet<WindowContainer> targets, ArrayMap<WindowContainer, ChangeInfo> changes) {
         final TransitionInfo out = new TransitionInfo(type, flags);
 
@@ -1048,6 +1069,10 @@
                 final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
                 task.fillTaskInfo(tinfo);
                 change.setTaskInfo(tinfo);
+                change.setRotationAnimation(getTaskRotationAnimation(task));
+                final ActivityRecord topMostActivity = task.getTopMostActivity();
+                change.setAllowEnterPip(topMostActivity != null
+                        && topMostActivity.checkEnterPictureInPictureAppOpsState());
             }
             out.addChange(change);
         }
@@ -1055,6 +1080,23 @@
         return out;
     }
 
+    private static int getTaskRotationAnimation(@NonNull Task task) {
+        final ActivityRecord top = task.getTopVisibleActivity();
+        if (top == null) return ROTATION_ANIMATION_UNSPECIFIED;
+        final WindowState mainWin = top.findMainWindow(false);
+        if (mainWin == null) return ROTATION_ANIMATION_UNSPECIFIED;
+        int anim = mainWin.getRotationAnimationHint();
+        if (anim >= 0) return anim;
+        anim = mainWin.getAttrs().rotationAnimation;
+        if (anim != ROTATION_ANIMATION_SEAMLESS) return anim;
+        if (mainWin != task.mDisplayContent.getDisplayPolicy().getTopFullscreenOpaqueWindow()
+                || !top.matchParentBounds()) {
+            // At the moment, we only support seamless rotation if there is only one window showing.
+            return ROTATION_ANIMATION_UNSPECIFIED;
+        }
+        return mainWin.getAttrs().rotationAnimation;
+    }
+
     boolean getLegacyIsReady() {
         return mState == STATE_STARTED && mSyncId >= 0 && mSyncEngine.isReady(mSyncId);
     }
@@ -1148,10 +1190,16 @@
             final DisplayContent dc = wc.asDisplayContent();
             if (dc != null) {
                 flags |= FLAG_IS_DISPLAY;
+                if (dc.hasAlertWindowSurfaces()) {
+                    flags |= FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+                }
             }
             if (isWallpaper(wc)) {
                 flags |= FLAG_IS_WALLPAPER;
             }
+            if (occludesKeyguard(wc)) {
+                flags |= FLAG_OCCLUDES_KEYGUARD;
+            }
             return flags;
         }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 416b9df..25f7269 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -93,7 +93,7 @@
     RemoteAnimationTarget createRemoteAnimationTarget() {
         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
                 mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
-                mWallpaperToken.getWindowConfiguration(), true, null, null, null);
+                mWallpaperToken.getWindowConfiguration(), true, null, null, null, false);
         return mTarget;
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 95e5fc2..0f61f1a 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+import static android.app.WallpaperManager.COMMAND_UNFREEZE;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
@@ -79,6 +81,8 @@
     private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
     private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
     private final float mMaxWallpaperScale;
+    // Whether COMMAND_FREEZE was dispatched.
+    private boolean mLastFrozen = false;
 
     // This is set when we are waiting for a wallpaper to tell us it is done
     // changing its scroll position.
@@ -194,6 +198,7 @@
                 if (DEBUG_WALLPAPER) Slog.v(TAG,
                         "Win " + w + ": token animating, looking behind.");
             }
+            mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground());
             // Found a target! End search.
             return true;
         }
@@ -424,20 +429,25 @@
     Bundle sendWindowWallpaperCommand(
             WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
         if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
-            boolean doWait = sync;
-            for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
-                final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
-                token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
-            }
-
-            if (doWait) {
-                // TODO: Need to wait for result.
-            }
+            sendWindowWallpaperCommand(action, x, y, z, extras, sync);
         }
 
         return null;
     }
 
+    private void sendWindowWallpaperCommand(
+                String action, int x, int y, int z, Bundle extras, boolean sync) {
+        boolean doWait = sync;
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
+            token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
+        }
+
+        if (doWait) {
+            // TODO: Need to wait for result.
+        }
+    }
+
     private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
         WindowState target = mWallpaperTarget;
         if (target != null) {
@@ -641,6 +651,13 @@
 
         updateWallpaperTokens(visible);
 
+        if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) {
+            mLastFrozen = mFindResults.isWallpaperTargetForLetterbox;
+            sendWindowWallpaperCommand(
+                    mFindResults.isWallpaperTargetForLetterbox ? COMMAND_FREEZE : COMMAND_UNFREEZE,
+                    /* x= */ 0, /* y= */ 0, /* z= */ 0, /* extras= */ null, /* sync= */ false);
+        }
+
         if (DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
                 + " prev=" + mPrevWallpaperTarget);
     }
@@ -838,6 +855,7 @@
         boolean useTopWallpaperAsTarget = false;
         WindowState wallpaperTarget = null;
         boolean resetTopWallpaper = false;
+        boolean isWallpaperTargetForLetterbox = false;
 
         void setTopWallpaper(WindowState win) {
             topWallpaper = win;
@@ -851,11 +869,16 @@
             useTopWallpaperAsTarget = topWallpaperAsTarget;
         }
 
+        void setIsWallpaperTargetForLetterbox(boolean isWallpaperTargetForLetterbox) {
+            this.isWallpaperTargetForLetterbox = isWallpaperTargetForLetterbox;
+        }
+
         void reset() {
             topWallpaper = null;
             wallpaperTarget = null;
             useTopWallpaperAsTarget = false;
             resetTopWallpaper = false;
+            isWallpaperTargetForLetterbox = false;
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ffee0b7..c48e9d1 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3400,6 +3400,29 @@
     }
 
     /**
+     * Forces the receiver container to always use the configuration of the supplier container as
+     * its requested override configuration. It allows to propagate configuration without changing
+     * the relationship between child and parent.
+     */
+    static void overrideConfigurationPropagation(WindowContainer<?> receiver,
+            WindowContainer<?> supplier) {
+        final ConfigurationContainerListener listener = new ConfigurationContainerListener() {
+            @Override
+            public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
+                receiver.onRequestedOverrideConfigurationChanged(supplier.getConfiguration());
+            }
+        };
+        supplier.registerConfigurationChangeListener(listener);
+        receiver.registerWindowContainerListener(new WindowContainerListener() {
+            @Override
+            public void onRemoved() {
+                receiver.unregisterWindowContainerListener(this);
+                supplier.unregisterConfigurationChangeListener(listener);
+            }
+        });
+    }
+
+    /**
      * Returns the {@link WindowManager.LayoutParams.WindowType}.
      */
     @WindowManager.LayoutParams.WindowType int getWindowType() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 2a271ef..6a6d3c9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -288,6 +288,16 @@
          * Called when drag operation was cancelled.
          */
         default void postCancelDragAndDrop() {}
+
+        /**
+         * Called when it has entered a View that is willing to accept the drop.
+         */
+        default void dragRecipientEntered(IWindow window) {}
+
+        /**
+         * Called when it has exited a View that is willing to accept the drop.
+         */
+        default void dragRecipientExited(IWindow window) {}
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ffbfe1e..3a5d771 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -452,14 +452,14 @@
     /**
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
-    public static final boolean sEnableRemoteKeyguardGoingAwayAnimation = !sEnableShellTransitions
-            && sEnableRemoteKeyguardAnimation >= 1;
+    public static final boolean sEnableRemoteKeyguardGoingAwayAnimation =
+            sEnableRemoteKeyguardAnimation >= 1;
 
     /**
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
-    public static final boolean sEnableRemoteKeyguardOccludeAnimation = !sEnableShellTransitions
-            && sEnableRemoteKeyguardAnimation >= 2;
+    public static final boolean sEnableRemoteKeyguardOccludeAnimation =
+            sEnableRemoteKeyguardAnimation >= 2;
 
     /**
      * Allows a fullscreen windowing mode activity to launch in its desired orientation directly
@@ -1769,9 +1769,8 @@
             final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
             win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
 
-            final ActivityRecord tokenActivity = token.asActivityRecord();
-            if (type == TYPE_APPLICATION_STARTING && tokenActivity != null) {
-                tokenActivity.mStartingWindow = win;
+            if (type == TYPE_APPLICATION_STARTING && activity != null) {
+                activity.attachStartingWindow(win);
                 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
                         activity, win);
             }
@@ -3050,7 +3049,7 @@
         mSettingsObserver.updateSystemUiSettings(true /* handleChange */);
         synchronized (mGlobalLock) {
             // force a re-application of focused window sysui visibility on each display.
-            mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
+            mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemBarAttributes);
         }
     }
 
@@ -5292,6 +5291,7 @@
                 case LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED: {
                     synchronized (mGlobalLock) {
                         final DisplayContent displayContent = (DisplayContent) msg.obj;
+                        displayContent.mLayoutAndAssignWindowLayersScheduled = false;
                         displayContent.layoutAndAssignWindowLayersIfNeeded();
                     }
                     break;
@@ -8668,4 +8668,9 @@
                     : DEFAULT_DISPLAY;
         }
     }
+
+    @Override
+    public void setTaskSnapshotEnabled(boolean enabled) {
+        mTaskSnapshotController.setTaskSnapshotEnabled(enabled);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index abf8afa..aa147c4 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -322,6 +322,7 @@
         int effects = 0;
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
         mService.deferWindowLayout();
+        mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
         try {
             if (transition != null) {
                 // First check if we have a display rotation transition and if so, update it.
@@ -411,6 +412,7 @@
                 task.setMainWindowSizeChangeTransaction(sft);
             }
             if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
+                mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
                 // Already calls ensureActivityConfig
                 mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
                 mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -432,6 +434,7 @@
                 mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
             }
         } finally {
+            mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
             mService.continueWindowLayout();
         }
     }
@@ -472,7 +475,15 @@
                 throw new UnsupportedOperationException("Not supported to set multi-window"
                         + " windowing mode during locked task mode.");
             }
+
+            final int prevMode = container.getWindowingMode();
             container.setWindowingMode(windowingMode);
+            if (prevMode != container.getWindowingMode()) {
+                // The activity in the container may become focusable or non-focusable due to
+                // windowing modes changes (such as entering or leaving pinned windowing mode),
+                // so also apply the lifecycle effects to this transaction.
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
+            }
         }
         return effects;
     }
@@ -720,8 +731,10 @@
                 fragmentToken = hop.getContainer();
                 final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
                 final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
-                final TaskFragment tf2 = mLaunchTaskFragments.get(adjacentFragmentToken);
-                if (tf1 == null || tf2 == null) {
+                final TaskFragment tf2 = adjacentFragmentToken != null
+                        ? mLaunchTaskFragments.get(adjacentFragmentToken)
+                        : null;
+                if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
                     final Throwable exception = new IllegalArgumentException(
                             "Not allowed to set adjacent on invalid fragment tokens");
                     sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
@@ -1169,7 +1182,12 @@
             return;
         }
         mLaunchTaskFragments.removeAt(index);
-        taskFragment.removeImmediately();
+        taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
+    }
+
+    @Nullable
+    TaskFragment getTaskFragment(IBinder tfToken) {
+        return mLaunchTaskFragments.get(tfToken);
     }
 
     static class CallerInfo {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 25dd75a..bee8bda 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1170,7 +1170,8 @@
         if (WindowManager.LayoutParams.isSystemAlertWindowType(mAttrs.type)) {
             return TouchOcclusionMode.USE_OPACITY;
         }
-        if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)) {
+        if (isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_ALL)
+                || mWmService.mAtmService.getTransitionController().inTransition(this)) {
             return TouchOcclusionMode.USE_OPACITY;
         }
         return TouchOcclusionMode.BLOCK_UNTRUSTED;
@@ -1441,6 +1442,14 @@
         }
     }
 
+    @Override
+    public Rect getBounds() {
+        // The window bounds are used for layout in screen coordinates. If the token has bounds for
+        // size compatibility mode, its configuration bounds are app based coordinates which should
+        // not be used for layout.
+        return mToken.hasSizeCompatBounds() ? mToken.getBounds() : super.getBounds();
+    }
+
     /** Retrieves the current frame of the window that the application sees. */
     Rect getFrame() {
         return mWindowFrames.mFrame;
@@ -4728,7 +4737,7 @@
         final int drawState = mWinAnimator.mDrawState;
         if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
             if (mAttrs.type != TYPE_APPLICATION_STARTING) {
-                mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
+                mActivityRecord.onFirstWindowDrawn(this);
             } else {
                 mActivityRecord.onStartingWindowDrawn();
             }
@@ -6044,8 +6053,11 @@
     }
 
     boolean hasWallpaper() {
-        return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
-                || (mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox());
+        return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0 || hasWallpaperForLetterboxBackground();
+    }
+
+    boolean hasWallpaperForLetterboxBackground() {
+        return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 0bb97f5..6204824 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -54,7 +54,8 @@
     private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
     private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
     private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
-    private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
+    static final String WINSCOPE_EXT = ".winscope";
+    private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace" + WINSCOPE_EXT;
     private static final String TAG = "WindowTracing";
     private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index ab4f1f6..8c93377 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -157,12 +157,12 @@
         "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
         "android.hardware.light@2.0",
-        "android.hardware.memtrack-V1-ndk_platform",
+        "android.hardware.memtrack-V1-ndk",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
         "android.hardware.power-V2-cpp",
         "android.hardware.power.stats@1.0",
-        "android.hardware.power.stats-V1-ndk_platform",
+        "android.hardware.power.stats-V1-ndk",
         "android.hardware.thermal@1.0",
         "android.hardware.tv.input@1.0",
         "android.hardware.vibrator-V2-cpp",
@@ -175,7 +175,7 @@
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
         "android.frameworks.stats@1.0",
-        "android.frameworks.stats-V1-ndk_platform",
+        "android.frameworks.stats-V1-ndk",
         "android.system.suspend.control-V1-cpp",
         "android.system.suspend.control.internal-cpp",
         "android.system.suspend@1.0",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7efe9d4..6a25965 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -327,7 +327,6 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo;
-import com.android.server.devicepolicy.Owners.OwnerDto;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.RestrictionsSet;
@@ -1259,17 +1258,37 @@
     }
 
     // Used by DevicePolicyManagerServiceShellCommand
-    List<OwnerDto> listAllOwners() {
+    List<OwnerShellData> listAllOwners() {
         Preconditions.checkCallAuthorization(
                 hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
         return mInjector.binderWithCleanCallingIdentity(() -> {
-            List<OwnerDto> owners = mOwners.listAllOwners();
+            SparseArray<DevicePolicyData> userData;
+
+            // Gets the owners of "full users" first (device owner and profile owners)
+            List<OwnerShellData> owners = mOwners.listAllOwners();
             synchronized (getLockObject()) {
                 for (int i = 0; i < owners.size(); i++) {
-                    OwnerDto owner = owners.get(i);
+                    OwnerShellData owner = owners.get(i);
                     owner.isAffiliated = isUserAffiliatedWithDeviceLocked(owner.userId);
                 }
+                userData = mUserData;
             }
+
+            // Then the owners of profile users (managed profiles)
+            for (int i = 0; i < userData.size(); i++) {
+                DevicePolicyData policyData = mUserData.valueAt(i);
+                int userId = userData.keyAt(i);
+                int parentUserId = mUserManagerInternal.getProfileParentId(userId);
+                boolean isProfile = parentUserId != userId;
+                if (!isProfile) continue;
+                for (int j = 0; j < policyData.mAdminList.size(); j++) {
+                    ActiveAdmin admin = policyData.mAdminList.get(j);
+                    OwnerShellData owner = OwnerShellData.forManagedProfileOwner(userId,
+                            parentUserId, admin.info.getComponent());
+                    owners.add(owner);
+                }
+            }
+
             return owners;
         });
     }
@@ -11577,14 +11596,11 @@
                 Preconditions.checkCallAuthorization(
                         isProfileOwner(caller) || isDeviceOwner(caller));
             }
-            long id = mInjector.binderClearCallingIdentity();
             try {
                 return mIPackageManager.getBlockUninstallForUser(packageName, userId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slogf.e(LOG_TAG, "Failed to getBlockUninstallForUser", re);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
             }
         }
         return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index a2db6aac..85fe65c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -22,8 +22,6 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 
-import com.android.server.devicepolicy.Owners.OwnerDto;
-
 import java.io.PrintWriter;
 import java.util.Collection;
 import java.util.List;
@@ -205,12 +203,12 @@
     }
 
     private int runListOwners(PrintWriter pw) {
-        List<OwnerDto> owners = mService.listAllOwners();
+        List<OwnerShellData> owners = mService.listAllOwners();
         int size = printAndGetSize(pw, owners, "owner");
         if (size == 0) return 0;
 
         for (int i = 0; i < size; i++) {
-            OwnerDto owner = owners.get(i);
+            OwnerShellData owner = owners.get(i);
             pw.printf("User %2d: admin=%s", owner.userId, owner.admin.flattenToShortString());
             if (owner.isDeviceOwner) {
                 pw.print(",DeviceOwner");
@@ -218,6 +216,9 @@
             if (owner.isProfileOwner) {
                 pw.print(",ProfileOwner");
             }
+            if (owner.isManagedProfileOwner) {
+                pw.printf(",ManagedProfileOwner(parentUserId=%d)", owner.parentUserId);
+            }
             if (owner.isAffiliated) {
                 pw.print(",Affiliated");
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java
new file mode 100644
index 0000000..b98c3dc
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import static android.os.UserHandle.USER_NULL;
+
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Data-transfer object used by {@link DevicePolicyManagerServiceShellCommand}.
+ */
+final class OwnerShellData {
+
+    public final @UserIdInt int userId;
+    public final @UserIdInt int parentUserId;
+    public final ComponentName admin;
+    public final boolean isDeviceOwner;
+    public final boolean isProfileOwner;
+    public final boolean isManagedProfileOwner;
+    public boolean isAffiliated;
+
+    // NOTE: class is too simple to require a Builder (not to mention isAffiliated is mutable)
+    private OwnerShellData(@UserIdInt int userId, @UserIdInt int parentUserId, ComponentName admin,
+            boolean isDeviceOwner, boolean isProfileOwner, boolean isManagedProfileOwner) {
+        Preconditions.checkArgument(userId != USER_NULL, "userId cannot be USER_NULL");
+        this.userId = userId;
+        this.parentUserId = parentUserId;
+        this.admin = Objects.requireNonNull(admin, "admin must not be null");
+        this.isDeviceOwner = isDeviceOwner;
+        this.isProfileOwner = isProfileOwner;
+        this.isManagedProfileOwner = isManagedProfileOwner;
+        if (isManagedProfileOwner) {
+            Preconditions.checkArgument(parentUserId != USER_NULL,
+                    "parentUserId cannot be USER_NULL for managed profile owner");
+            Preconditions.checkArgument(parentUserId != userId,
+                    "cannot be parent of itself (%d)", userId);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(getClass().getSimpleName())
+                .append("[userId=").append(userId)
+                .append(",admin=").append(admin.flattenToShortString());
+        if (isDeviceOwner) {
+            sb.append(",deviceOwner");
+        }
+        if (isProfileOwner) {
+            sb.append(",isProfileOwner");
+        }
+        if (isManagedProfileOwner) {
+            sb.append(",isManagedProfileOwner");
+        }
+        if (parentUserId != USER_NULL) {
+            sb.append(",parentUserId=").append(parentUserId);
+        }
+        if (isAffiliated) {
+            sb.append(",isAffiliated");
+        }
+        return sb.append(']').toString();
+    }
+
+    static OwnerShellData forDeviceOwner(@UserIdInt int userId, ComponentName admin) {
+        return new OwnerShellData(userId, /* parentUserId= */ USER_NULL, admin,
+                /* isDeviceOwner= */ true, /* isProfileOwner= */ false,
+                /* isManagedProfileOwner= */ false);
+    }
+
+    static OwnerShellData forUserProfileOwner(@UserIdInt int userId, ComponentName admin) {
+        return new OwnerShellData(userId, /* parentUserId= */ USER_NULL, admin,
+                /* isDeviceOwner= */ false, /* isProfileOwner= */ true,
+                /* isManagedProfileOwner= */ false);
+    }
+
+    static OwnerShellData forManagedProfileOwner(@UserIdInt int userId, @UserIdInt int parentUserId,
+            ComponentName admin) {
+        return new OwnerShellData(userId, parentUserId, admin, /* isDeviceOwner= */ false,
+                /* isProfileOwner= */ false, /* isManagedProfileOwner= */ true);
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fd09e3f..3584728 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -19,7 +19,6 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManagerInternal;
 import android.app.admin.DevicePolicyManager.DeviceOwnerType;
@@ -476,17 +475,16 @@
         }
     }
 
-    List<OwnerDto> listAllOwners() {
-        List<OwnerDto> owners = new ArrayList<>();
+    List<OwnerShellData> listAllOwners() {
+        List<OwnerShellData> owners = new ArrayList<>();
         synchronized (mLock) {
             if (mDeviceOwner != null) {
-                owners.add(new OwnerDto(mDeviceOwnerUserId, mDeviceOwner.admin,
-                        /* isDeviceOwner= */ true));
+                owners.add(OwnerShellData.forDeviceOwner(mDeviceOwnerUserId, mDeviceOwner.admin));
             }
             for (int i = 0; i < mProfileOwners.size(); i++) {
                 int userId = mProfileOwners.keyAt(i);
                 OwnerInfo info = mProfileOwners.valueAt(i);
-                owners.add(new OwnerDto(userId, info.admin, /* isDeviceOwner= */ false));
+                owners.add(OwnerShellData.forUserProfileOwner(userId, info.admin));
             }
         }
         return owners;
@@ -1236,24 +1234,6 @@
         }
     }
 
-    /**
-     * Data-transfer object used by {@link DevicePolicyManagerServiceShellCommand}.
-     */
-    static final class OwnerDto {
-        public final @UserIdInt int userId;
-        public final ComponentName admin;
-        public final boolean isDeviceOwner;
-        public final boolean isProfileOwner;
-        public boolean isAffiliated;
-
-        private OwnerDto(@UserIdInt int userId, ComponentName admin, boolean isDeviceOwner) {
-            this.userId = userId;
-            this.admin = Objects.requireNonNull(admin, "admin must not be null");
-            this.isDeviceOwner = isDeviceOwner;
-            this.isProfileOwner = !isDeviceOwner;
-        }
-    }
-
     public void dump(IndentingPrintWriter pw) {
         boolean needBlank = false;
         if (mDeviceOwner != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 787f588..0010015 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -286,6 +286,8 @@
             "com.android.server.job.JobSchedulerService";
     private static final String LOCK_SETTINGS_SERVICE_CLASS =
             "com.android.server.locksettings.LockSettingsService$Lifecycle";
+    private static final String RESOURCE_ECONOMY_SERVICE_CLASS =
+            "com.android.server.tare.InternalResourceService";
     private static final String STORAGE_MANAGER_SERVICE_CLASS =
             "com.android.server.StorageManagerService$Lifecycle";
     private static final String STORAGE_STATS_SERVICE_CLASS =
@@ -1465,6 +1467,12 @@
                 t.traceEnd();
             }
 
+            // TODO(aml-jobscheduler): Think about how to do it properly.
+            t.traceBegin("StartResourceEconomy");
+            mSystemServiceManager.startService(RESOURCE_ECONOMY_SERVICE_CLASS);
+            t.traceEnd();
+
+            // TODO(aml-jobscheduler): Think about how to do it properly.
             t.traceBegin("StartAlarmManagerService");
             mSystemServiceManager.startService(ALARM_MANAGER_SERVICE_CLASS);
             t.traceEnd();
@@ -1585,6 +1593,9 @@
             // all listeners have the chance to react with special handling.
             Settings.Global.putInt(context.getContentResolver(),
                     Settings.Global.AIRPLANE_MODE_ON, 1);
+        } else if (context.getResources().getBoolean(R.bool.config_autoResetAirplaneMode)) {
+            Settings.Global.putInt(context.getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 0);
         }
 
         StatusBarManagerService statusBar = null;
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index 988c02b..1bcc3d1 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -32,6 +32,7 @@
         "androidx.test.runner",
         "junit",
         "kotlin-test",
+        "kotlin-reflect",
         "services.core",
         "servicestests-utils",
         "truth-prebuilt",
diff --git a/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING b/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING
new file mode 100644
index 0000000..cacfcf0
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "PackageManagerServiceUnitTests"
+    }
+  ]
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
new file mode 100644
index 0000000..a7644ec
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.ConfigurationInfo
+import android.content.pm.FeatureGroupInfo
+import android.content.pm.FeatureInfo
+import android.content.pm.PackageManager
+import android.content.pm.SigningDetails
+import android.content.pm.parsing.ParsingPackage
+import android.content.pm.parsing.component.ParsedActivity
+import android.content.pm.parsing.component.ParsedAttribution
+import android.content.pm.parsing.component.ParsedComponent
+import android.content.pm.parsing.component.ParsedInstrumentation
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.content.pm.parsing.component.ParsedPermission
+import android.content.pm.parsing.component.ParsedPermissionGroup
+import android.content.pm.parsing.component.ParsedProcess
+import android.content.pm.parsing.component.ParsedProvider
+import android.content.pm.parsing.component.ParsedService
+import android.content.pm.parsing.component.ParsedUsesPermission
+import android.net.Uri
+import android.os.Bundle
+import android.os.Parcelable
+import android.util.ArraySet
+import android.util.SparseArray
+import android.util.SparseIntArray
+import com.android.internal.R
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
+import java.security.KeyPairGenerator
+import java.security.PublicKey
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, PackageImpl::class) {
+
+    override val defaultImpl = PackageImpl.forTesting("com.example.test")
+    override val creator = PackageImpl.CREATOR
+
+    override val excludedMethods = listOf(
+        // Internal methods
+        "toAppInfoToString",
+        "toAppInfoWithoutState",
+        "toAppInfoWithoutStateWithoutFlags",
+        "assignDerivedFields",
+        "buildFakeForDeletion",
+        "capPermissionPriorities",
+        "forParsing",
+        "forTesting",
+        "getBaseAppDataCredentialProtectedDirForSystemUser",
+        "getBaseAppDataDeviceProtectedDirForSystemUser",
+        "getBoolean",
+        "setBoolean",
+        "hideAsFinal",
+        "hideAsParsed",
+        "markNotActivitiesAsNotExportedIfSingleUser",
+        "sortActivities",
+        "sortReceivers",
+        "sortServices",
+        "setAllComponentsDirectBootAware",
+        // Tested through setting minor/major manually
+        "setLongVersionCode",
+        "getLongVersionCode",
+        // Tested through constructor
+        "getManifestPackageName",
+        "setManifestPackageName",
+        // Utility methods
+        "getStorageUuid",
+        // Removal not tested, irrelevant for parcelling concerns
+        "removeUsesOptionalLibrary",
+        "clearAdoptPermissions",
+        "clearOriginalPackages",
+        "clearProtectedBroadcasts",
+        "removePermission",
+        "removeUsesLibrary",
+        "removeUsesOptionalNativeLibrary",
+        // Tested manually
+        "getMimeGroups",
+        "getRequestedPermissions",
+        // Tested through asSplit
+        "asSplit",
+        "getSplitNames",
+        "getSplitCodePaths",
+        "getSplitRevisionCodes",
+        "getSplitFlags",
+        "getSplitClassLoaderNames",
+        "getSplitDependencies",
+        "setSplitCodePaths",
+        "setSplitClassLoaderName",
+        "setSplitHasCode",
+    )
+
+    override val baseParams = listOf(
+        AndroidPackage::getAppComponentFactory,
+        AndroidPackage::getAutoRevokePermissions,
+        AndroidPackage::getBackupAgentName,
+        AndroidPackage::getBanner,
+        AndroidPackage::getBaseApkPath,
+        AndroidPackage::getBaseRevisionCode,
+        AndroidPackage::getCategory,
+        AndroidPackage::getClassLoaderName,
+        AndroidPackage::getClassName,
+        AndroidPackage::getCompatibleWidthLimitDp,
+        AndroidPackage::getCompileSdkVersion,
+        AndroidPackage::getCompileSdkVersionCodeName,
+        AndroidPackage::getDataExtractionRules,
+        AndroidPackage::getDescriptionRes,
+        AndroidPackage::getFullBackupContent,
+        AndroidPackage::getGwpAsanMode,
+        AndroidPackage::getIconRes,
+        AndroidPackage::getInstallLocation,
+        AndroidPackage::getLabelRes,
+        AndroidPackage::getLargestWidthLimitDp,
+        AndroidPackage::getLogo,
+        AndroidPackage::getManageSpaceActivityName,
+        AndroidPackage::getMemtagMode,
+        AndroidPackage::getMinSdkVersion,
+        AndroidPackage::getNativeHeapZeroInitialized,
+        AndroidPackage::getNativeLibraryDir,
+        AndroidPackage::getNativeLibraryRootDir,
+        AndroidPackage::getNetworkSecurityConfigRes,
+        AndroidPackage::getNonLocalizedLabel,
+        AndroidPackage::getOverlayCategory,
+        AndroidPackage::getOverlayPriority,
+        AndroidPackage::getOverlayTarget,
+        AndroidPackage::getOverlayTargetName,
+        AndroidPackage::getPackageName,
+        AndroidPackage::getPath,
+        AndroidPackage::getPermission,
+        AndroidPackage::getPrimaryCpuAbi,
+        AndroidPackage::getProcessName,
+        AndroidPackage::getRealPackage,
+        AndroidPackage::getRequiredAccountType,
+        AndroidPackage::getRequiresSmallestWidthDp,
+        AndroidPackage::getResizeableActivity,
+        AndroidPackage::getRestrictedAccountType,
+        AndroidPackage::getRoundIconRes,
+        AndroidPackage::getSeInfo,
+        AndroidPackage::getSeInfoUser,
+        AndroidPackage::getSecondaryCpuAbi,
+        AndroidPackage::getSecondaryNativeLibraryDir,
+        AndroidPackage::getSharedUserId,
+        AndroidPackage::getSharedUserLabel,
+        AndroidPackage::getStaticSharedLibName,
+        AndroidPackage::getStaticSharedLibVersion,
+        AndroidPackage::getTargetSandboxVersion,
+        AndroidPackage::getTargetSdkVersion,
+        AndroidPackage::getTaskAffinity,
+        AndroidPackage::getTheme,
+        AndroidPackage::getUiOptions,
+        AndroidPackage::getUid,
+        AndroidPackage::getVersionName,
+        AndroidPackage::getZygotePreloadName,
+        AndroidPackage::isAllowAudioPlaybackCapture,
+        AndroidPackage::isAllowBackup,
+        AndroidPackage::isAllowClearUserData,
+        AndroidPackage::isAllowClearUserDataOnFailedRestore,
+        AndroidPackage::isAllowNativeHeapPointerTagging,
+        AndroidPackage::isAllowTaskReparenting,
+        AndroidPackage::isBackupInForeground,
+        AndroidPackage::isBaseHardwareAccelerated,
+        AndroidPackage::isCantSaveState,
+        AndroidPackage::isCoreApp,
+        AndroidPackage::isCrossProfile,
+        AndroidPackage::isDebuggable,
+        AndroidPackage::isDefaultToDeviceProtectedStorage,
+        AndroidPackage::isDirectBootAware,
+        AndroidPackage::isEnabled,
+        AndroidPackage::isExternalStorage,
+        AndroidPackage::isExtractNativeLibs,
+        AndroidPackage::isFactoryTest,
+        AndroidPackage::isForceQueryable,
+        AndroidPackage::isFullBackupOnly,
+        AndroidPackage::isGame,
+        AndroidPackage::isHasCode,
+        AndroidPackage::isHasDomainUrls,
+        AndroidPackage::isHasFragileUserData,
+        AndroidPackage::isIsolatedSplitLoading,
+        AndroidPackage::isKillAfterRestore,
+        AndroidPackage::isLargeHeap,
+        AndroidPackage::isMultiArch,
+        AndroidPackage::isNativeLibraryRootRequiresIsa,
+        AndroidPackage::isOdm,
+        AndroidPackage::isOem,
+        AndroidPackage::isOverlay,
+        AndroidPackage::isOverlayIsStatic,
+        AndroidPackage::isPartiallyDirectBootAware,
+        AndroidPackage::isPersistent,
+        AndroidPackage::isPrivileged,
+        AndroidPackage::isProduct,
+        AndroidPackage::isProfileableByShell,
+        AndroidPackage::isRequestLegacyExternalStorage,
+        AndroidPackage::isRequiredForAllUsers,
+        AndroidPackage::isResizeableActivityViaSdkVersion,
+        AndroidPackage::isRestoreAnyVersion,
+        AndroidPackage::isSignedWithPlatformKey,
+        AndroidPackage::isStaticSharedLibrary,
+        AndroidPackage::isStub,
+        AndroidPackage::isSupportsRtl,
+        AndroidPackage::isSystem,
+        AndroidPackage::isSystemExt,
+        AndroidPackage::isTestOnly,
+        AndroidPackage::isUse32BitAbi,
+        AndroidPackage::isUseEmbeddedDex,
+        AndroidPackage::isUsesCleartextTraffic,
+        AndroidPackage::isUsesNonSdkApi,
+        AndroidPackage::isVendor,
+        AndroidPackage::isVisibleToInstantApps,
+        AndroidPackage::isVmSafeMode,
+        AndroidPackage::getMaxAspectRatio,
+        AndroidPackage::getMinAspectRatio,
+        AndroidPackage::hasPreserveLegacyExternalStorage,
+        AndroidPackage::hasRequestForegroundServiceExemption,
+        AndroidPackage::hasRequestRawExternalStorageAccess,
+    )
+
+    override fun extraParams() = listOf(
+        getter(AndroidPackage::getVolumeUuid, "57554103-df3e-4475-ae7a-8feba49353ac"),
+        getter(AndroidPackage::isProfileable, true),
+        getter(AndroidPackage::getVersionCode, 3),
+        getter(AndroidPackage::getVersionCodeMajor, 9),
+        getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")),
+        getter(AndroidPackage::isAnyDensity, false, 0),
+        getter(AndroidPackage::isResizeable, false, 0),
+        getter(AndroidPackage::isSupportsSmallScreens, false, 0),
+        getter(AndroidPackage::isSupportsNormalScreens, false, 0),
+        getter(AndroidPackage::isSupportsLargeScreens, false, 0),
+        getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0),
+        adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"),
+        adder(AndroidPackage::getOriginalPackages, "com.test.original"),
+        adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"),
+        adder(AndroidPackage::getLibraryNames, "testLibraryName"),
+        adder(AndroidPackage::getProtectedBroadcasts, "test.protected.BROADCAST"),
+        adder(AndroidPackage::getQueriesPackages, "com.test.package.queries"),
+        adder(AndroidPackage::getQueriesProviders, "com.test.package.queries.provider"),
+        adder(AndroidPackage::getUsesLibraries, "testUsesLibrary"),
+        adder(AndroidPackage::getUsesNativeLibraries, "testUsesNativeLibrary"),
+        adder(AndroidPackage::getUsesOptionalLibraries, "testUsesOptionalLibrary"),
+        adder(AndroidPackage::getUsesOptionalNativeLibraries, "testUsesOptionalNativeLibrary"),
+        adder(AndroidPackage::getUsesStaticLibraries, "testUsesStaticLibrary"),
+        getSetByValue(
+            AndroidPackage::getUsesStaticLibrariesVersions,
+            PackageImpl::addUsesStaticLibraryVersion,
+            (testCounter++).toLong(),
+            transformGet = { it?.singleOrNull() }
+        ),
+        getSetByValue(
+            AndroidPackage::areAttributionsUserVisible,
+            ParsingPackage::setAttributionsAreUserVisible,
+            true
+        ),
+        getSetByValue2(
+            AndroidPackage::getOverlayables,
+            PackageImpl::addOverlayable,
+            "testOverlayableName" to "testActorName",
+            transformGet = { "testOverlayableName" to it["testOverlayableName"] }
+        ),
+        getSetByValue(
+            AndroidPackage::getMetaData,
+            PackageImpl::setMetaData,
+            "testBundleKey" to "testBundleValue",
+            transformGet = { "testBundleKey" to it?.getString("testBundleKey") },
+            transformSet = { Bundle().apply { putString(it.first, it.second) } }
+        ),
+        getSetByValue(
+            AndroidPackage::getAttributions,
+            PackageImpl::addAttribution,
+            Triple("testTag", 13, listOf("testInherit")),
+            transformGet = { it.singleOrNull()?.let { Triple(it.tag, it.label, it.inheritFrom) } },
+            transformSet = { it?.let { ParsedAttribution(it.first, it.second, it.third) } }
+        ),
+        getSetByValue2(
+            AndroidPackage::getKeySetMapping,
+            PackageImpl::addKeySet,
+            "testKeySetName" to testKey(),
+            transformGet = { "testKeySetName" to it["testKeySetName"]?.singleOrNull() },
+        ),
+        getSetByValue(
+            AndroidPackage::getPermissionGroups,
+            PackageImpl::addPermissionGroup,
+            "test.permission.GROUP",
+            transformGet = { it.singleOrNull()?.name },
+            transformSet = { ParsedPermissionGroup().apply { setName(it) } }
+        ),
+        getSetByValue2(
+            AndroidPackage::getPreferredActivityFilters,
+            PackageImpl::addPreferredActivityFilter,
+            "TestClassName" to ParsedIntentInfo().apply {
+                addDataScheme("http")
+                addDataAuthority("test.pm.server.android.com", null)
+            },
+            transformGet = { it.singleOrNull()?.let { it.first to it.second } },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    { it.first },
+                    { it.second.schemesIterator().asSequence().singleOrNull() },
+                    { it.second.authoritiesIterator().asSequence().singleOrNull()?.host },
+                )
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getQueriesIntents,
+            PackageImpl::addQueriesIntent,
+            Intent(Intent.ACTION_VIEW, Uri.parse("https://test.pm.server.android.com")),
+            transformGet = { it.singleOrNull() },
+            compare = { first, second -> first?.filterEquals(second) },
+        ),
+        getSetByValue(
+            AndroidPackage::getRestrictUpdateHash,
+            PackageImpl::setRestrictUpdateHash,
+            byteArrayOf(0, 1, 2, 3, 4),
+            compare = ByteArray::contentEquals
+        ),
+        getSetByValue(
+            AndroidPackage::getSigningDetails,
+            PackageImpl::setSigningDetails,
+            testKey(),
+            transformGet = { it.publicKeys?.takeIf { it.size > 0 }?.valueAt(0) },
+            transformSet = {
+                SigningDetails(
+                    null,
+                    SigningDetails.SignatureSchemeVersion.UNKNOWN,
+                    ArraySet<PublicKey>().apply { add(it) },
+                    null
+                )
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getUsesStaticLibrariesCertDigests,
+            PackageImpl::addUsesStaticLibraryCertDigests,
+            arrayOf("testCertDigest"),
+            transformGet = { it?.singleOrNull() },
+            compare = Array<String?>?::contentEquals
+        ),
+        getSetByValue(
+            AndroidPackage::getActivities,
+            PackageImpl::addActivity,
+            "TestActivityName",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() }
+        ),
+        getSetByValue(
+            AndroidPackage::getReceivers,
+            PackageImpl::addReceiver,
+            "TestReceiverName",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() }
+        ),
+        getSetByValue(
+            AndroidPackage::getServices,
+            PackageImpl::addService,
+            "TestServiceName",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedService().apply { name = it }.withMimeGroups() }
+        ),
+        getSetByValue(
+            AndroidPackage::getProviders,
+            PackageImpl::addProvider,
+            "TestProviderName",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedProvider().apply { name = it }.withMimeGroups() }
+        ),
+        getSetByValue(
+            AndroidPackage::getInstrumentations,
+            PackageImpl::addInstrumentation,
+            "TestInstrumentationName",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedInstrumentation().apply { name = it } }
+        ),
+        getSetByValue(
+            AndroidPackage::getConfigPreferences,
+            PackageImpl::addConfigPreference,
+            testCounter++,
+            transformGet = { it.singleOrNull()?.reqGlEsVersion ?: -1 },
+            transformSet = { ConfigurationInfo().apply { reqGlEsVersion = it } }
+        ),
+        getSetByValue(
+            AndroidPackage::getFeatureGroups,
+            PackageImpl::addFeatureGroup,
+            "test.feature.GROUP",
+            transformGet = { it.singleOrNull()?.features?.singleOrNull()?.name.orEmpty() },
+            transformSet = {
+                FeatureGroupInfo().apply {
+                    features = arrayOf(FeatureInfo().apply { name = it })
+                }
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getPermissions,
+            PackageImpl::addPermission,
+            "test.PERMISSION",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { ParsedPermission().apply { name = it } }
+        ),
+        getSetByValue(
+            AndroidPackage::getUsesPermissions,
+            PackageImpl::addUsesPermission,
+            "test.USES_PERMISSION",
+            transformGet = {
+                // Need to strip implicit permission, which calls addUsesPermission when added
+                it.filterNot { it.name == "test.implicit.PERMISSION" }
+                    .singleOrNull()?.name.orEmpty()
+            },
+            transformSet = { ParsedUsesPermission(it, 0) }
+        ),
+        getSetByValue(
+            AndroidPackage::getReqFeatures,
+            PackageImpl::addReqFeature,
+            "test.feature.INFO",
+            transformGet = { it.singleOrNull()?.name.orEmpty() },
+            transformSet = { FeatureInfo().apply { name = it } }
+        ),
+        getSetByValue(
+            AndroidPackage::getMinExtensionVersions,
+            PackageImpl::setMinExtensionVersions,
+            SparseIntArray().apply { put(testCounter++, testCounter++) },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    { it.size() },
+                    { it.keyAt(0) },
+                    { it.valueAt(0) },
+                )
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getProcesses,
+            PackageImpl::setProcesses,
+            mapOf("testProcess" to ParsedProcess().apply { name = "testProcessName" }),
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    { it["testProcess"]?.name },
+                )
+            }
+        ),
+        getSetByValue(
+            AndroidPackage::getProperties,
+            PackageImpl::addProperty,
+            PackageManager.Property(
+                "testPropertyName",
+                "testPropertyValue",
+                "testPropertyClassName",
+                "testPropertyPackageName"
+            ),
+            transformGet = { it["testPropertyName"] },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    PackageManager.Property::getName,
+                    PackageManager.Property::getClassName,
+                    PackageManager.Property::getPackageName,
+                    PackageManager.Property::getString,
+                )
+            }
+        ),
+    )
+
+    override fun initialObject() = PackageImpl.forParsing(
+        "com.example.test",
+        "/test/test/base.apk",
+        "/test/test",
+        mockThrowOnUnmocked {
+            whenever(getInteger(R.styleable.AndroidManifest_revisionCode, 0)) { 4 }
+            whenever(getBoolean(R.styleable.AndroidManifest_isolatedSplits, false)) { true }
+
+            // Return invalid values here so that the getter/setter is tested properly
+            whenever(getInteger(R.styleable.AndroidManifest_versionCode, 0)) { -1 }
+            whenever(getInteger(R.styleable.AndroidManifest_versionCodeMajor, 0)) { -1 }
+            whenever(
+                getNonConfigurationString(
+                    R.styleable.AndroidManifest_versionName,
+                    0
+                )
+            ) { "" }
+            whenever(getInteger(R.styleable.AndroidManifest_compileSdkVersion, 0)) { 31 }
+            whenever(
+                getNonConfigurationString(
+                    R.styleable.AndroidManifest_compileSdkVersionCodename,
+                    0
+                )
+            ) { "" }
+        },
+        true
+    )
+        .asSplit(
+            arrayOf("testSplitNameZero", "testSplitNameOne"),
+            arrayOf("/test/testSplitZero.apk", "/test/testSplitOne.apk"),
+            intArrayOf(10, 11),
+            SparseArray<IntArray>().apply {
+                put(0, intArrayOf(-1))
+                put(1, intArrayOf(0))
+            }
+        )
+        .setSplitHasCode(0, true)
+        .setSplitHasCode(1, false)
+        .setSplitClassLoaderName(0, "testSplitClassLoaderNameZero")
+        .setSplitClassLoaderName(1, "testSplitClassLoaderNameOne")
+
+    override fun extraAssertions(before: Parcelable, after: Parcelable) {
+        super.extraAssertions(before, after)
+        after as PackageImpl
+        expect.that(after.manifestPackageName).isEqualTo("com.example.test")
+        expect.that(after.isCoreApp).isTrue()
+        expect.that(after.isIsolatedSplitLoading).isEqualTo(true)
+        expect.that(after.longVersionCode).isEqualTo(38654705667)
+        expect.that(after.requestedPermissions)
+            .containsExactlyElementsIn(after.usesPermissions.map { it.name })
+            .inOrder()
+
+        expect.that(after.mimeGroups).containsExactly(
+            "TestActivityName/mimeGroup",
+            "TestReceiverName/mimeGroup",
+            "TestServiceName/mimeGroup",
+            "TestProviderName/mimeGroup"
+        )
+
+        expect.that(after.splitNames).asList()
+            .containsExactly("testSplitNameZero", "testSplitNameOne")
+            .inOrder()
+        expect.that(after.splitCodePaths).asList()
+            .containsExactly("/test/testSplitZero.apk", "/test/testSplitOne.apk")
+            .inOrder()
+        expect.that(after.splitRevisionCodes).asList()
+            .containsExactly(10, 11)
+            .inOrder()
+        expect.that(after.splitFlags).asList()
+            .containsExactly(ApplicationInfo.FLAG_HAS_CODE, 0)
+            .inOrder()
+        expect.that(after.splitClassLoaderNames).asList()
+            .containsExactly("testSplitClassLoaderNameZero", "testSplitClassLoaderNameOne")
+            .inOrder()
+
+        expect.that(after.splitDependencies).isNotNull()
+        after.splitDependencies?.let {
+            expect.that(it.size()).isEqualTo(2)
+            expect.that(it.get(0)).asList().containsExactly(-1)
+            expect.that(it.get(1)).asList().containsExactly(0)
+        }
+    }
+
+    private fun testKey() = KeyPairGenerator.getInstance("RSA")
+        .generateKeyPair()
+        .public
+
+    private fun <T : ParsedComponent> T.withMimeGroups() = apply {
+        val componentName = name
+        addIntent(ParsedIntentInfo().apply {
+            addMimeGroup("$componentName/mimeGroup")
+        })
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt
new file mode 100644
index 0000000..e16a187
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableComponentTest.kt
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.os.Parcel
+import android.os.Parcelable
+import com.android.server.pm.test.util.IgnoreableExpect
+import com.google.common.truth.Expect
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import java.util.Objects
+import kotlin.contracts.ExperimentalContracts
+import kotlin.reflect.KClass
+import kotlin.reflect.KFunction
+import kotlin.reflect.KFunction1
+import kotlin.reflect.KFunction2
+import kotlin.reflect.KFunction3
+import kotlin.reflect.KVisibility
+import kotlin.reflect.full.allSuperclasses
+import kotlin.reflect.full.createInstance
+import kotlin.reflect.full.isSubclassOf
+import kotlin.reflect.full.memberFunctions
+import kotlin.reflect.full.memberProperties
+import kotlin.reflect.full.staticProperties
+import kotlin.reflect.jvm.jvmErasure
+
+
+@ExperimentalContracts
+abstract class ParcelableComponentTest(
+    private val getterType: KClass<*>,
+    private val setterType: KClass<out Parcelable>
+) {
+
+    companion object {
+        private val DEFAULT_EXCLUDED = listOf(
+            // Java
+            "toString",
+            "equals",
+            "hashCode",
+            // Parcelable
+            "getStability",
+            "describeContents",
+            "writeToParcel",
+            // @DataClass
+            "__metadata"
+        )
+    }
+
+    internal val ignoreableExpect = IgnoreableExpect()
+
+    // Hides internal type
+    @get:Rule
+    val ignoreableAsTestRule: TestRule = ignoreableExpect
+
+    val expect: Expect
+        get() = ignoreableExpect.expect
+
+    protected var testCounter = 1
+
+    protected abstract val defaultImpl: Any
+    protected abstract val creator: Parcelable.Creator<out Parcelable>
+
+    protected open val excludedMethods: Collection<String> = emptyList()
+
+    protected abstract val baseParams: Collection<KFunction1<*, Any?>>
+
+    private val getters = getterType.memberFunctions
+        .filterNot { DEFAULT_EXCLUDED.contains(it.name) }
+
+    private val setters = setterType.memberFunctions
+        .filterNot { DEFAULT_EXCLUDED.contains(it.name) }
+
+    constructor(kClass: KClass<out Parcelable>) : this(kClass, kClass)
+
+    @Before
+    fun checkNoPublicFields() {
+        // Fields are not currently testable, and the idea is to enforce interface access for
+        // immutability purposes, so disallow any public fields from existing.
+        expect.that(getterType.memberProperties.filter { it.visibility == KVisibility.PUBLIC }
+            .filterNot { DEFAULT_EXCLUDED.contains(it.name) })
+            .isEmpty()
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <ObjectType, ReturnType> buildParams(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+    ): Param? {
+        return buildParams<ObjectType, ReturnType, ReturnType, ReturnType>(
+            getFunction,
+            autoValue(getFunction) as ReturnType ?: return null
+        )
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> buildParams(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        value: SetType,
+    ): Param? {
+        return getSetByValue<ObjectType, ReturnType, SetType, Any?>(
+            getFunction,
+            findSetFunction(getFunction) ?: return null,
+            value
+        )
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <ObjectType, ReturnType> findSetFunction(
+        getFunction: KFunction1<ObjectType, ReturnType>
+    ): KFunction2<ObjectType, ReturnType, Any?>? {
+        val getFunctionName = getFunction.name
+        val prefix = when {
+            getFunctionName.startsWith("get") -> "get"
+            getFunctionName.startsWith("is") -> "is"
+            getFunctionName.startsWith("has") -> "has"
+            else -> throw IllegalArgumentException("Unsupported method name $getFunctionName")
+        }
+        val setFunctionName = "set" + getFunctionName.removePrefix(prefix)
+        val setFunction = setters.filter { it.name == setFunctionName }
+            .minByOrNull { it.parameters.size }
+
+        if (setFunction == null) {
+            expect.withMessage("$getFunctionName does not have corresponding $setFunctionName")
+                .fail()
+            return null
+        }
+
+        return setFunction as KFunction2<ObjectType, ReturnType, Any?>
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <ObjectType, ReturnType, SetType> findAddFunction(
+        getFunction: KFunction1<ObjectType, ReturnType>
+    ): KFunction2<ObjectType, SetType, Any?>? {
+        val getFunctionName = getFunction.name
+        if (!getFunctionName.startsWith("get")) {
+            throw IllegalArgumentException("Unsupported method name $getFunctionName")
+        }
+
+        val setFunctionName = "add" + getFunctionName.removePrefix("get").run {
+            // Remove plurality
+            when {
+                endsWith("ies") -> "${removeSuffix("ies")}y"
+                endsWith("s") -> removeSuffix("s")
+                else -> this
+            }
+        }
+
+        val setFunction = setters.filter { it.name == setFunctionName }
+            .minByOrNull { it.parameters.size }
+
+        if (setFunction == null) {
+            expect.withMessage("$getFunctionName does not have corresponding $setFunctionName")
+                .fail()
+            return null
+        }
+
+        return setFunction as KFunction2<ObjectType, SetType, Any?>
+    }
+
+    protected fun <ObjectType, ReturnType> getter(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        valueToSet: ReturnType
+    ) = buildParams<ObjectType, ReturnType, ReturnType, ReturnType>(getFunction, valueToSet)
+
+    protected fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> getter(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        expectedValue: CompareType,
+        valueToSet: SetType
+    ): Param? {
+        return getSetByValue(
+            getFunction,
+            findSetFunction(getFunction) ?: return null,
+            value = expectedValue,
+            transformSet = { valueToSet }
+        )
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    protected fun <ObjectType, ReturnType> adder(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        value: ReturnType,
+    ): Param? {
+        return getSetByValue(
+            getFunction,
+            findAddFunction<ObjectType, Any?, ReturnType>(getFunction) ?: return null,
+            value,
+            transformGet = {
+                // Primitive arrays don't implement Iterable, so cast manually
+                when (it) {
+                    is BooleanArray -> it.singleOrNull()
+                    is IntArray -> it.singleOrNull()
+                    is LongArray -> it.singleOrNull()
+                    is Iterable<*> -> it.singleOrNull()
+                    else -> null
+                }
+            },
+        )
+    }
+
+    /**
+     * Method to provide custom getter and setter logic for values which are not simple primitives
+     * or cannot be directly compared using [Objects.equals].
+     *
+     * @param getFunction the getter function which will be called and marked as tested
+     * @param setFunction the setter function which will be called and marked as tested
+     * @param value the value for comparison through the parcel-unparcel cycle, which can be
+     *          anything, like the [String] ID of an inner object
+     * @param transformGet the function to transform the result of [getFunction] into [value]
+     * @param transformSet the function to transform [value] into an input for [setFunction]
+     * @param compare the function that compares the pre/post-parcel [value] objects
+     */
+    @Suppress("UNCHECKED_CAST")
+    protected fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> getSetByValue(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        setFunction: KFunction2<ObjectType, SetType, Any?>,
+        value: CompareType,
+        transformGet: (ReturnType) -> CompareType = { it as CompareType },
+        transformSet: (CompareType) -> SetType = { it as SetType },
+        compare: (CompareType, CompareType) -> Boolean? = Objects::equals
+    ) = Param(
+        getFunction.name,
+        { transformGet(getFunction.call(it as ObjectType)) },
+        setFunction.name,
+        { setFunction.call(it.first() as ObjectType, transformSet(it[1] as CompareType)) },
+        { value },
+        { first, second -> compare(first as CompareType, second as CompareType) == true }
+    )
+
+    /**
+     * Variant of [getSetByValue] that allows specifying a [setFunction] with 2 inputs.
+     */
+    @Suppress("UNCHECKED_CAST")
+    protected fun <ObjectType, ReturnType, SetType1 : Any?, SetType2 : Any?, CompareType : Any?>
+            getSetByValue2(
+        getFunction: KFunction1<ObjectType, ReturnType>,
+        setFunction: KFunction3<ObjectType, SetType1, SetType2, Any>,
+        value: CompareType,
+        transformGet: (ReturnType) -> CompareType = { it as CompareType },
+        transformSet: (CompareType) -> Pair<SetType1, SetType2> =
+            { it as Pair<SetType1, SetType2> },
+        compare: (CompareType, CompareType) -> Boolean = Objects::equals
+    ) = Param(
+        getFunction.name,
+        { transformGet(getFunction.call(it as ObjectType)) },
+        setFunction.name,
+        {
+            val pair = transformSet(it[1] as CompareType)
+            setFunction.call(it.first() as ObjectType, pair.first, pair.second)
+        },
+        { value },
+        { first, second -> compare(first as CompareType, second as CompareType) }
+    )
+
+    protected fun autoValue(getFunction: KFunction<*>) = when (getFunction.returnType.jvmErasure) {
+        Boolean::class -> (getFunction.call(defaultImpl) as Boolean?)?.not() ?: true
+        CharSequence::class,
+        String::class -> getFunction.name + "TEST"
+        Int::class -> testCounter++
+        Long::class -> (testCounter++).toLong()
+        Float::class -> (testCounter++).toFloat()
+        else -> {
+            expect.withMessage("${getFunction.name} needs to provide value").fail()
+            null
+        }
+    }
+
+    /**
+     * Verifies two instances are equivalent via a series of properties. For use when a public API
+     * class has not implemented equals.
+     */
+    @Suppress("UNCHECKED_CAST")
+    protected fun <T : Any> equalBy(
+        first: T?,
+        second: T?,
+        vararg properties: (T) -> Any?
+    ) = properties.all { property ->
+        first?.let { property(it) } == second?.let { property(it) }
+    }
+
+    @Test
+    fun valueComparison() {
+        val params = baseParams.mapNotNull(::buildParams) + extraParams().filterNotNull()
+        val before = initialObject()
+
+        params.forEach { it.setFunction(arrayOf(before, it.value())) }
+
+        val parcel = Parcel.obtain()
+        writeToParcel(parcel, before)
+
+        val dataSize = parcel.dataSize()
+
+        parcel.setDataPosition(0)
+
+        val after = creator.createFromParcel(parcel)
+
+        expect.withMessage("Mismatched write and read data sizes")
+            .that(parcel.dataPosition())
+            .isEqualTo(dataSize)
+
+        parcel.recycle()
+
+        runAssertions(params, before, after)
+    }
+
+    @Test
+    open fun parcellingSize() {
+        val parcelOne = Parcel.obtain()
+        writeToParcel(parcelOne, initialObject())
+
+        val parcelTwo = Parcel.obtain()
+        initialObject().writeToParcel(parcelTwo, 0)
+
+        val superDataSizes = setterType.allSuperclasses
+            .filter { it.isSubclassOf(Parcelable::class) }
+            .mapNotNull { it.memberFunctions.find { it.name == "writeToParcel" } }
+            .filter { it.isFinal }
+            .map {
+                val parcel = Parcel.obtain()
+                initialObject().writeToParcel(parcel, 0)
+                parcel.dataSize().also { parcel.recycle() }
+            }
+
+        if ((superDataSizes + parcelOne.dataSize() + parcelTwo.dataSize()).distinct().size != 1) {
+            listOf(getterType, setterType).distinct().forEach {
+                val creatorProperties = it.staticProperties.filter { it.name == "CREATOR" }
+                if (creatorProperties.size > 1) {
+                    expect.withMessage(
+                        "Multiple matching CREATOR fields found for" +
+                                it.qualifiedName
+                    )
+                        .that(creatorProperties)
+                        .hasSize(1)
+                } else {
+                    val creator = creatorProperties.single().get()
+                    if (creator !is Parcelable.Creator<*>) {
+                        expect.that(creator).isInstanceOf(Parcelable.Creator::class.java)
+                        return
+                    }
+
+                    parcelTwo.setDataPosition(0)
+                    val parcelable = creator.createFromParcel(parcelTwo)
+                    if (parcelable::class.isSubclassOf(setterType)) {
+                        expect.withMessage(
+                            "${it.qualifiedName} which does not safely override writeToParcel " +
+                                    "cannot contain a subclass CREATOR field"
+                        )
+                            .fail()
+                    }
+                }
+            }
+        }
+
+        parcelOne.recycle()
+        parcelTwo.recycle()
+    }
+
+    private fun runAssertions(params: List<Param>, before: Parcelable, after: Parcelable) {
+        params.forEach {
+            val actual = it.getFunction(after)
+            val expected = it.value()
+            val equal = it.compare(actual, expected)
+            expect.withMessage("${it.getFunctionName} was $actual, expected $expected")
+                .that(equal)
+                .isTrue()
+        }
+
+        extraAssertions(before, after)
+
+        // TODO: Handle method overloads?
+        val expectedFunctions = (getters.map { it.name }
+                + setters.map { it.name }
+                - excludedMethods)
+            .distinct()
+
+        val allTestedFunctions = params.flatMap {
+            listOfNotNull(it.getFunctionName, it.setFunctionName)
+        }
+        expect.that(allTestedFunctions).containsExactlyElementsIn(expectedFunctions)
+    }
+
+    open fun extraParams(): Collection<Param?> = emptyList()
+
+    open fun initialObject(): Parcelable = setterType.createInstance()
+
+    open fun extraAssertions(before: Parcelable, after: Parcelable) {}
+
+    open fun writeToParcel(parcel: Parcel, value: Parcelable) = value.writeToParcel(parcel, 0)
+
+    data class Param(
+        val getFunctionName: String,
+        val getFunction: (Any?) -> Any?,
+        val setFunctionName: String?,
+        val setFunction: (Array<Any?>) -> Unit,
+        val value: () -> Any?,
+        val compare: (Any?, Any?) -> Boolean = Objects::equals
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt
new file mode 100644
index 0000000..d506190
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorInvalidTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.os.Parcel
+import android.os.Parcelable
+import com.android.server.pm.test.parsing.parcelling.java.TestSubWithCreator
+import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass
+import org.junit.Test
+import kotlin.contracts.ExperimentalContracts
+
+/**
+ * Verifies the failing side of [ParcelableCreatorValidTest]. The sole difference is the addition
+ * of [TestSubWithCreator.CREATOR].
+ */
+@ExperimentalContracts
+class ParcelableCreatorInvalidTest :
+    ParcelableComponentTest(TestSuperClass::class, TestSubWithCreator::class) {
+
+    override val defaultImpl = TestSubWithCreator()
+
+    override val creator = object : Parcelable.Creator<Parcelable> {
+        override fun createFromParcel(source: Parcel) = TestSubWithCreator(source)
+        override fun newArray(size: Int) = Array<TestSubWithCreator?>(size) { null }
+    }
+
+    override val excludedMethods = listOf("writeSubToParcel")
+
+    override val baseParams = listOf(TestSuperClass::getSuperString)
+
+    override fun writeToParcel(parcel: Parcel, value: Parcelable) {
+        (value as TestSubWithCreator).writeSubToParcel(parcel, 0)
+    }
+
+    @Test
+    override fun parcellingSize() {
+        super.parcellingSize()
+        if (expect.hasFailures()) {
+            // This is a hack to ignore an expected failure result. Doing it this way, rather than
+            // adding a switch in the test itself, prevents it from accidentally passing through a
+            // programming error.
+            ignoreableExpect.ignore()
+        }
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt
new file mode 100644
index 0000000..f1bc7b5
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParcelableCreatorValidTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.os.Parcel
+import android.os.Parcelable
+import com.android.server.pm.test.parsing.parcelling.java.TestSubWithoutCreator
+import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass
+import kotlin.contracts.ExperimentalContracts
+
+/**
+ * Tests the [Parcelable] CREATOR verification by using a mock object with known differences to
+ * ensure that the method succeeds/fails.
+ */
+@ExperimentalContracts
+class ParcelableCreatorValidTest :
+    ParcelableComponentTest(TestSuperClass::class, TestSubWithoutCreator::class) {
+
+    override val defaultImpl = TestSubWithoutCreator()
+
+    override val creator = object : Parcelable.Creator<Parcelable> {
+        override fun createFromParcel(source: Parcel) = TestSubWithoutCreator(source)
+        override fun newArray(size: Int) = Array<TestSubWithoutCreator?>(size) { null }
+    }
+
+    override val excludedMethods = listOf("writeSubToParcel")
+
+    override val baseParams = listOf(TestSuperClass::getSuperString)
+
+    override fun writeToParcel(parcel: Parcel, value: Parcelable) {
+        (value as TestSubWithoutCreator).writeSubToParcel(parcel, 0)
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
new file mode 100644
index 0000000..ece600b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.ActivityInfo
+import android.content.pm.parsing.component.ParsedActivity
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedActivityTest : ParsedMainComponentTest(ParsedActivity::class) {
+
+    override val defaultImpl = ParsedActivity()
+    override val creator = ParsedActivity.CREATOR
+
+    override val mainComponentSubclassBaseParams = listOf(
+        ParsedActivity::getPermission,
+        ParsedActivity::getColorMode,
+        ParsedActivity::getConfigChanges,
+        ParsedActivity::getDocumentLaunchMode,
+        ParsedActivity::getLaunchMode,
+        ParsedActivity::getLockTaskLaunchMode,
+        ParsedActivity::getMaxAspectRatio,
+        ParsedActivity::getMaxRecents,
+        ParsedActivity::getMinAspectRatio,
+        ParsedActivity::getParentActivityName,
+        ParsedActivity::getPersistableMode,
+        ParsedActivity::getPrivateFlags,
+        ParsedActivity::getRequestedVrComponent,
+        ParsedActivity::getResizeMode,
+        ParsedActivity::getRotationAnimation,
+        ParsedActivity::getScreenOrientation,
+        ParsedActivity::getSoftInputMode,
+        ParsedActivity::getTargetActivity,
+        ParsedActivity::getTaskAffinity,
+        ParsedActivity::getTheme,
+        ParsedActivity::getUiOptions,
+        ParsedActivity::isSupportsSizeChanges,
+    )
+
+    override fun mainComponentSubclassExtraParams() = listOf(
+        getSetByValue(
+            ParsedActivity::getWindowLayout,
+            ParsedActivity::setWindowLayout,
+            ActivityInfo.WindowLayout(1, 1f, 2, 1f, 3, 4, 5),
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    ActivityInfo.WindowLayout::width,
+                    ActivityInfo.WindowLayout::widthFraction,
+                    ActivityInfo.WindowLayout::height,
+                    ActivityInfo.WindowLayout::heightFraction,
+                    ActivityInfo.WindowLayout::gravity,
+                    ActivityInfo.WindowLayout::minWidth,
+                    ActivityInfo.WindowLayout::minHeight
+                )
+            }
+        )
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
new file mode 100644
index 0000000..e739dc7
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedAttribution
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedAttributionTest : ParcelableComponentTest(ParsedAttribution::class) {
+
+    override val defaultImpl = ParsedAttribution("", 0, emptyList())
+    override val creator = ParsedAttribution.CREATOR
+
+    override val baseParams = listOf(
+        ParsedAttribution::getTag,
+        ParsedAttribution::getLabel,
+    )
+
+    override fun extraParams() = listOf(
+        getter(ParsedAttribution::getInheritFrom, listOf("testInheritFrom"))
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
new file mode 100644
index 0000000..0a22f6d
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.PackageManager
+import android.content.pm.parsing.component.ParsedComponent
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.os.Bundle
+import android.os.Parcelable
+import kotlin.contracts.ExperimentalContracts
+import kotlin.reflect.KClass
+import kotlin.reflect.KFunction1
+
+@ExperimentalContracts
+abstract class ParsedComponentTest(kClass: KClass<out Parcelable>) :
+    ParcelableComponentTest(kClass) {
+
+    final override val excludedMethods
+        get() = subclassExcludedMethods + listOf(
+            // Method aliases/utilities
+            "getClassName",
+            "getComponentName",
+            "setProperties" // Tested though addProperty
+        )
+
+    open val subclassExcludedMethods: Collection<String> = emptyList()
+
+    final override val baseParams
+        get() = subclassBaseParams + listOf(
+            ParsedComponent::getBanner,
+            ParsedComponent::getDescriptionRes,
+            ParsedComponent::getFlags,
+            ParsedComponent::getIcon,
+            ParsedComponent::getLabelRes,
+            ParsedComponent::getLogo,
+            ParsedComponent::getName,
+            ParsedComponent::getNonLocalizedLabel,
+            ParsedComponent::getPackageName,
+        )
+
+    abstract val subclassBaseParams: Collection<KFunction1<*, Any?>>
+
+    final override fun extraParams() = subclassExtraParams() + listOf(
+        getSetByValue(
+            ParsedComponent::getIntents,
+            ParsedComponent::addIntent,
+            "TestLabel",
+            transformGet = { it.singleOrNull()?.nonLocalizedLabel },
+            transformSet = { ParsedIntentInfo().setNonLocalizedLabel(it) },
+        ),
+        getSetByValue(
+            ParsedComponent::getProperties,
+            ParsedComponent::addProperty,
+            PackageManager.Property(
+                "testPropertyName",
+                "testPropertyValue",
+                "testPropertyClassName",
+                "testPropertyPackageName"
+            ),
+            transformGet = { it["testPropertyName"] },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    PackageManager.Property::getName,
+                    PackageManager.Property::getClassName,
+                    PackageManager.Property::getPackageName,
+                    PackageManager.Property::getString,
+                )
+            }
+        ),
+        getSetByValue(
+            ParsedComponent::getMetaData,
+            ParsedComponent::setMetaData,
+            "testBundleKey" to "testBundleValue",
+            transformGet = { "testBundleKey" to it?.getString("testBundleKey") },
+            transformSet = { Bundle().apply { putString(it.first, it.second) } }
+        ),
+    )
+
+    open fun subclassExtraParams(): Collection<Param?> = emptyList()
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
new file mode 100644
index 0000000..b7a85cc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedInstrumentation
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedInstrumentationTest : ParsedComponentTest(ParsedInstrumentation::class) {
+
+    override val defaultImpl = ParsedInstrumentation()
+    override val creator = ParsedInstrumentation.CREATOR
+
+    override val subclassBaseParams = listOf(
+        ParsedInstrumentation::getTargetPackage,
+        ParsedInstrumentation::getTargetProcesses,
+        ParsedInstrumentation::isFunctionalTest,
+        ParsedInstrumentation::isHandleProfiling,
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
new file mode 100644
index 0000000..e27bdf2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.os.Parcel
+import android.os.Parcelable
+import android.os.PatternMatcher
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedIntentInfoTest : ParcelableComponentTest(ParsedIntentInfo::class) {
+
+    override val defaultImpl = ParsedIntentInfo()
+
+    override val creator = object : Parcelable.Creator<ParsedIntentInfo> {
+        override fun createFromParcel(source: Parcel) = ParsedIntentInfo(source)
+        override fun newArray(size: Int) = Array<ParsedIntentInfo?>(size) { null }
+    }
+
+    override val excludedMethods = listOf(
+        // Used to parcel
+        "writeIntentInfoToParcel",
+        // All remaining IntentFilter methods, which are out of scope
+        "hasDataPath",
+        "hasDataSchemeSpecificPart",
+        "matchAction",
+        "matchData",
+        "actionsIterator",
+        "addAction",
+        "addCategory",
+        "addDataAuthority",
+        "addDataPath",
+        "addDataScheme",
+        "addDataSchemeSpecificPart",
+        "addDataType",
+        "addDynamicDataType",
+        "addMimeGroup",
+        "asPredicate",
+        "asPredicateWithTypeResolution",
+        "authoritiesIterator",
+        "categoriesIterator",
+        "clearDynamicDataTypes",
+        "countActions",
+        "countCategories",
+        "countDataAuthorities",
+        "countDataPaths",
+        "countDataSchemeSpecificParts",
+        "countDataSchemes",
+        "countDataTypes",
+        "countMimeGroups",
+        "countStaticDataTypes",
+        "dataTypes",
+        "debugCheck",
+        "dump",
+        "dumpDebug",
+        "getAction",
+        "getAutoVerify",
+        "getCategory",
+        "getDataAuthority",
+        "getDataPath",
+        "getDataScheme",
+        "getDataSchemeSpecificPart",
+        "getDataType",
+        "getHosts",
+        "getHostsList",
+        "getMimeGroup",
+        "getOrder",
+        "getPriority",
+        "getVisibilityToInstantApp",
+        "handleAllWebDataURI",
+        "handlesWebUris",
+        "hasAction",
+        "hasCategory",
+        "hasDataAuthority",
+        "hasDataScheme",
+        "hasDataType",
+        "hasExactDataType",
+        "hasExactDynamicDataType",
+        "hasExactStaticDataType",
+        "hasMimeGroup",
+        "isExplicitlyVisibleToInstantApp",
+        "isImplicitlyVisibleToInstantApp",
+        "isVerified",
+        "isVisibleToInstantApp",
+        "match",
+        "matchCategories",
+        "matchDataAuthority",
+        "mimeGroupsIterator",
+        "needsVerification",
+        "pathsIterator",
+        "readFromXml",
+        "schemeSpecificPartsIterator",
+        "schemesIterator",
+        "setAutoVerify",
+        "setOrder",
+        "setPriority",
+        "setVerified",
+        "setVisibilityToInstantApp",
+        "typesIterator",
+        "writeToXml",
+    )
+
+    override val baseParams = listOf(
+        ParsedIntentInfo::getIcon,
+        ParsedIntentInfo::getLabelRes,
+        ParsedIntentInfo::isHasDefault,
+        ParsedIntentInfo::getNonLocalizedLabel,
+    )
+
+    override fun initialObject() = ParsedIntentInfo().apply {
+        addAction("test.ACTION")
+        addDataAuthority("testAuthority", "404")
+        addCategory("test.CATEGORY")
+        addMimeGroup("testMime")
+        addDataPath("testPath", PatternMatcher.PATTERN_LITERAL)
+    }
+
+    override fun extraAssertions(before: Parcelable, after: Parcelable) {
+        super.extraAssertions(before, after)
+        after as ParsedIntentInfo
+        expect.that(after.actionsIterator().asSequence().singleOrNull())
+            .isEqualTo("test.ACTION")
+
+        val authority = after.authoritiesIterator().asSequence().singleOrNull()
+        expect.that(authority?.host).isEqualTo("testAuthority")
+        expect.that(authority?.port).isEqualTo(404)
+
+        expect.that(after.categoriesIterator().asSequence().singleOrNull())
+            .isEqualTo("test.CATEGORY")
+        expect.that(after.mimeGroupsIterator().asSequence().singleOrNull())
+            .isEqualTo("testMime")
+        expect.that(after.hasDataPath("testPath")).isTrue()
+    }
+
+    override fun writeToParcel(parcel: Parcel, value: Parcelable) =
+        ParsedIntentInfo.PARCELER.parcel(value as ParsedIntentInfo, parcel, 0)
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
new file mode 100644
index 0000000..411cb09
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedMainComponent
+import android.content.pm.parsing.component.ParsedService
+import android.os.Parcelable
+import java.util.Arrays
+import kotlin.contracts.ExperimentalContracts
+import kotlin.reflect.KClass
+import kotlin.reflect.KFunction1
+
+@ExperimentalContracts
+abstract class ParsedMainComponentTest(kClass: KClass<out Parcelable>) :
+    ParsedComponentTest(kClass) {
+
+    final override val subclassBaseParams
+        get() = mainComponentSubclassBaseParams + listOf(
+            ParsedMainComponent::getOrder,
+            ParsedMainComponent::getProcessName,
+            ParsedMainComponent::getSplitName,
+            ParsedMainComponent::isDirectBootAware,
+            ParsedMainComponent::isEnabled,
+            ParsedMainComponent::isExported,
+        )
+
+    abstract val mainComponentSubclassBaseParams: Collection<KFunction1<*, Any?>>
+
+    final override fun subclassExtraParams() = mainComponentSubclassExtraParams() + listOf(
+        getSetByValue(
+            ParsedService::getAttributionTags,
+            ParsedService::setAttributionTags,
+            arrayOf("testAttributionTag"),
+            compare = Arrays::equals
+        ),
+    )
+
+    open fun mainComponentSubclassExtraParams(): Collection<Param?> = emptyList()
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
new file mode 100644
index 0000000..53c862a
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedPermissionGroup
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedPermissionGroupTest : ParsedComponentTest(ParsedPermissionGroup::class) {
+
+    override val defaultImpl = ParsedPermissionGroup()
+    override val creator = ParsedPermissionGroup.CREATOR
+
+    override val subclassBaseParams = listOf(
+        ParsedPermissionGroup::getRequestDetailResourceId,
+        ParsedPermissionGroup::getBackgroundRequestDetailResourceId,
+        ParsedPermissionGroup::getBackgroundRequestResourceId,
+        ParsedPermissionGroup::getRequestRes,
+        ParsedPermissionGroup::getPriority,
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
new file mode 100644
index 0000000..bb63e2e2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedPermission
+import android.content.pm.parsing.component.ParsedPermissionGroup
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedPermissionTest : ParsedComponentTest(ParsedPermission::class) {
+
+    override val defaultImpl = ParsedPermission()
+    override val creator = ParsedPermission.CREATOR
+
+    override val subclassExcludedMethods = listOf(
+        // Utility methods
+        "isAppOp",
+        "isRuntime",
+        "getProtection",
+        "getProtectionFlags",
+        "calculateFootprint",
+        "setKnownCert", // Tested through setKnownCerts
+    )
+    override val subclassBaseParams = listOf(
+        ParsedPermission::getBackgroundPermission,
+        ParsedPermission::getGroup,
+        ParsedPermission::getRequestRes,
+        ParsedPermission::getProtectionLevel,
+        ParsedPermission::isTree,
+    )
+
+    override fun subclassExtraParams() = listOf(
+        getter(ParsedPermission::getKnownCerts, setOf("testCert")),
+        getSetByValue(
+            ParsedPermission::getParsedPermissionGroup,
+            ParsedPermission::setParsedPermissionGroup,
+            ParsedPermissionGroup().apply { name = "test.permission.group" },
+            compare = { first, second -> equalBy(first, second, ParsedPermissionGroup::getName) }
+        ),
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
new file mode 100644
index 0000000..34f46f2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedProcess
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedProcessTest : ParcelableComponentTest(ParsedProcess::class) {
+
+    override val defaultImpl = ParsedProcess()
+    override val creator = ParsedProcess.CREATOR
+
+    override val excludedMethods = listOf(
+        // Copying method
+        "addStateFrom",
+    )
+
+    override val baseParams = listOf(
+        ParsedProcess::getName,
+        ParsedProcess::getGwpAsanMode,
+        ParsedProcess::getMemtagMode,
+        ParsedProcess::getNativeHeapZeroInitialized,
+    )
+
+    override fun extraParams() = listOf(
+        getter(ParsedProcess::getDeniedPermissions, setOf("testDeniedPermission"))
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
new file mode 100644
index 0000000..e6d5c0f
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.PathPermission
+import android.content.pm.parsing.component.ParsedProvider
+import android.os.PatternMatcher
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedProviderTest : ParsedMainComponentTest(ParsedProvider::class) {
+
+    override val defaultImpl = ParsedProvider()
+    override val creator = ParsedProvider.CREATOR
+
+    override val mainComponentSubclassBaseParams = listOf(
+        ParsedProvider::getAuthority,
+        ParsedProvider::isSyncable,
+        ParsedProvider::getReadPermission,
+        ParsedProvider::getWritePermission,
+        ParsedProvider::isGrantUriPermissions,
+        ParsedProvider::isForceUriPermissions,
+        ParsedProvider::isMultiProcess,
+        ParsedProvider::getInitOrder,
+    )
+
+    override fun mainComponentSubclassExtraParams() = listOf(
+        getSetByValue(
+            ParsedProvider::getUriPermissionPatterns,
+            ParsedProvider::setUriPermissionPatterns,
+            PatternMatcher("testPattern", PatternMatcher.PATTERN_LITERAL),
+            transformGet = { it?.singleOrNull() },
+            transformSet = { arrayOf(it) },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    PatternMatcher::getPath,
+                    PatternMatcher::getType
+                )
+            }
+        ),
+        getSetByValue(
+            ParsedProvider::getPathPermissions,
+            ParsedProvider::setPathPermissions,
+            PathPermission(
+                "testPermissionPattern",
+                PatternMatcher.PATTERN_LITERAL,
+                "test.READ_PERMISSION",
+                "test.WRITE_PERMISSION"
+            ),
+            transformGet = { it?.singleOrNull() },
+            transformSet = { arrayOf(it) },
+            compare = { first, second ->
+                equalBy(
+                    first, second,
+                    PatternMatcher::getPath,
+                    PatternMatcher::getType,
+                    PathPermission::getReadPermission,
+                    PathPermission::getWritePermission,
+                )
+            }
+        )
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
new file mode 100644
index 0000000..5530184
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedService
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedServiceTest : ParsedMainComponentTest(ParsedService::class) {
+
+    override val defaultImpl = ParsedService()
+    override val creator = ParsedService.CREATOR
+
+    override val mainComponentSubclassBaseParams = listOf(
+        ParsedService::getForegroundServiceType,
+        ParsedService::getPermission,
+    )
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
new file mode 100644
index 0000000..1131c72
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling
+
+import android.content.pm.parsing.component.ParsedUsesPermission
+import android.os.Parcelable
+import kotlin.contracts.ExperimentalContracts
+
+@ExperimentalContracts
+class ParsedUsesPermissionTest : ParcelableComponentTest(ParsedUsesPermission::class) {
+
+    override val defaultImpl = ParsedUsesPermission("", 0)
+    override val creator = ParsedUsesPermission.CREATOR
+
+    override val baseParams = listOf(
+        ParsedUsesPermission::getName,
+        ParsedUsesPermission::getUsesPermissionFlags
+    )
+
+    override fun initialObject() = ParsedUsesPermission("", 0)
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java
new file mode 100644
index 0000000..581d2b2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithCreator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling.java;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+
+public class TestSubWithCreator extends TestSuperClass {
+
+    @NonNull
+    public static final Parcelable.Creator<TestSubWithCreator> CREATOR =
+            new Parcelable.Creator<TestSubWithCreator>() {
+                @Override
+                public TestSubWithCreator createFromParcel(Parcel source) {
+                    return new TestSubWithCreator(source);
+                }
+
+                @Override
+                public TestSubWithCreator[] newArray(int size) {
+                    return new TestSubWithCreator[size];
+                }
+            };
+
+    @Nullable
+    private String subString;
+
+    public TestSubWithCreator() {
+    }
+
+    public TestSubWithCreator(@NonNull Parcel in) {
+        super(in);
+        subString = in.readString();
+    }
+
+    public void writeSubToParcel(@NonNull Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeString(subString);
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java
new file mode 100644
index 0000000..4264a11
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSubWithoutCreator.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling.java;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import androidx.annotation.NonNull;
+
+public class TestSubWithoutCreator extends TestSuperClass {
+
+    @Nullable
+    private String subString;
+
+    public TestSubWithoutCreator() {
+    }
+
+    public TestSubWithoutCreator(@NonNull Parcel in) {
+        super(in);
+        subString = in.readString();
+    }
+
+    public void writeSubToParcel(@NonNull Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeString(subString);
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java
new file mode 100644
index 0000000..a009786
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.parsing.parcelling.java;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+@DataClass(genGetters = true, genSetters = true, genBuilder = false, genAidl = false,
+        genParcelable = true, genConstructor = false)
+public class TestSuperClass implements Parcelable {
+
+    @Nullable
+    private String superString;
+
+    public TestSuperClass() {
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    public @Nullable String getSuperString() {
+        return superString;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull TestSuperClass setSuperString(@NonNull String value) {
+        superString = value;
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (superString != null) flg |= 0x1;
+        dest.writeByte(flg);
+        if (superString != null) dest.writeString(superString);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected TestSuperClass(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        String _superString = (flg & 0x1) == 0 ? null : in.readString();
+
+        this.superString = _superString;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<TestSuperClass> CREATOR
+            = new Parcelable.Creator<TestSuperClass>() {
+        @Override
+        public TestSuperClass[] newArray(int size) {
+            return new TestSuperClass[size];
+        }
+
+        @Override
+        public TestSuperClass createFromParcel(@NonNull android.os.Parcel in) {
+            return new TestSuperClass(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1624381019144L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java",
+            inputSignatures = "private @android.annotation.Nullable java.lang.String superString\nclass TestSuperClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genAidl=false, genParcelable=true, genConstructor=false)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt
new file mode 100644
index 0000000..afb18f5
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/util/IgnoreableExpect.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.util
+
+import com.google.common.truth.Expect
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Wrapper for [Expect] which supports ignoring any failures. This should be used with caution, but
+ * it allows a base test to be written which doesn't switch success/failure in the test itself,
+ * preventing any logic errors from causing the test to accidentally succeed.
+ */
+internal class IgnoreableExpect : TestRule {
+
+    val expect = Expect.create()
+
+    private var ignore = false
+
+    override fun apply(base: Statement?, description: Description?): Statement {
+        return object : Statement() {
+            override fun evaluate() {
+                ignore = false
+                try {
+                    expect.apply(base, description).evaluate()
+                } catch (t: Throwable) {
+                    if (!ignore) {
+                        throw t
+                    }
+                }
+            }
+        }
+    }
+
+    fun ignore() {
+        ignore = true
+    }
+}
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 17a5dcc..3cab5ec 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
     <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission
         android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java
new file mode 100644
index 0000000..b3dc3ed
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActiveServicesTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
+import static org.junit.Assert.assertEquals;
+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.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+
+import android.app.compat.CompatChanges;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ServiceInfo;
+import android.os.SystemClock;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class ActiveServicesTest {
+
+    private static final long DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN = 10 * 1000;
+    private static final long[] DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = {
+            0,
+            DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN,
+            DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN * 2,
+            DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN * 3
+    };
+
+    private MockitoSession mMockingSession;
+    private ActivityManagerService mService;
+    private ActiveServices mActiveServices;
+    private AppProfiler mProfiler;
+
+    @Before
+    public void setUp() {
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .mockStatic(CompatChanges.class)
+                .startMocking();
+        prepareTestRescheduleServiceRestarts();
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockingSession != null) {
+            mMockingSession.finishMocking();
+        }
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testRescheduleServiceRestartsOnChanges() throws Exception {
+        final long now = SystemClock.uptimeMillis();
+        final long btwn = mService.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
+        final long rd0 = 0;
+        final long rd1 = 1000;
+        final long rd2 = rd1 + btwn;
+        final long rd3 = rd2 + btwn;
+        final long rd4 = rd3 + btwn * 10;
+        final long rd5 = rd4 + btwn;
+        int memFactor = ADJ_MEM_FACTOR_MODERATE;
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+        fillInRestartingServices(now, new long[] {rd0, rd1, rd2, rd3, rd4, rd5});
+
+        // Test enable/disable.
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(false, true, now);
+        long extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        verifyDelays(now, new long[] {rd0, extra, btwn + extra * 2, btwn * 2 + extra * 3, rd4,
+                rd5 + extra});
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(true, false, now);
+        verifyDelays(now, new long[] {rd0, rd1, rd2, rd3, rd4, rd5});
+
+        final long elapsed = 10;
+        final long now2 = now + elapsed;
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(false, true, now2);
+        verifyDelays(now2, new long[] {rd0 - elapsed, extra - elapsed,
+                btwn + extra * 2 - elapsed, btwn * 2 + extra * 3 - elapsed, rd4 - elapsed,
+                rd5 + extra - elapsed});
+
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(true, false, now2);
+        verifyDelays(now2, new long[] {rd0 - elapsed, rd1 - elapsed, rd2 - elapsed, rd3 - elapsed,
+                rd4 - elapsed, rd5 - elapsed});
+
+        // Test memory level changes.
+        memFactor = ADJ_MEM_FACTOR_LOW;
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+        extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        final long elapsed3 = elapsed * 2;
+        final long now3 = now + elapsed3;
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                ADJ_MEM_FACTOR_MODERATE, memFactor, "test", now3);
+        verifyDelays(now3, new long[] {rd0 - elapsed3, extra - elapsed3,
+                btwn + extra * 2 - elapsed3, btwn * 2 + extra * 3 - elapsed3, rd4 - elapsed3,
+                rd5 + extra - elapsed3});
+
+        memFactor = ADJ_MEM_FACTOR_CRITICAL;
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+        extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        final long elapsed4 = elapsed * 3;
+        final long now4 = now + elapsed4;
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                ADJ_MEM_FACTOR_LOW, memFactor, "test", now4);
+        verifyDelays(now4, new long[] {rd0 - elapsed4, extra - elapsed4,
+                btwn + extra * 2 - elapsed4, btwn * 2 + extra * 3 - elapsed4,
+                btwn * 3 + extra * 4 - elapsed4, btwn * 4 + extra * 5 - elapsed4});
+
+        memFactor = ADJ_MEM_FACTOR_MODERATE;
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+        extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        final long elapsed5 = elapsed * 4;
+        final long now5 = now + elapsed5;
+        mActiveServices.rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                ADJ_MEM_FACTOR_CRITICAL, memFactor, "test", now5);
+        verifyDelays(now5, new long[] {rd0 - elapsed5, extra - elapsed5,
+                btwn + extra * 2 - elapsed5, btwn * 2 + extra * 3 - elapsed5,
+                rd4 - elapsed5, rd5 + extra - elapsed5});
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    public void testRescheduleServiceRestartsOnOtherChanges() throws Exception {
+        final long now = SystemClock.uptimeMillis();
+        final long btwn = mService.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
+        final long rd0 = 1000;
+        final long rd1 = 2000;
+        final long rd2 = btwn * 10;
+        final long rd3 = 5000;
+        final long rd4 = btwn * 11 + 5000;
+        final long rd5 = 3000;
+        int memFactor = ADJ_MEM_FACTOR_CRITICAL;
+        long extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+
+        fillInRestartingServices(now, new long[] {rd0, rd1, rd2, rd3, rd4, rd5});
+        setNextRestarts(now, new long[] {extra, btwn + extra * 2, btwn * 2 + extra * 3,
+                btwn * 3 + extra * 4, btwn * 4 + extra * 5, btwn * 5 + extra * 6});
+        mActiveServices.mRestartingServices.remove(1);
+        mActiveServices.rescheduleServiceRestartIfPossibleLocked(extra, btwn, "test", now);
+        verifyDelays(now, new long[] {extra, rd2, rd2 + btwn +  extra,
+                rd2 + (btwn + extra) * 2, rd2 + (btwn + extra) * 3});
+        mActiveServices.mRestartingServices.remove(0);
+        mActiveServices.rescheduleServiceRestartIfPossibleLocked(extra, btwn, "test", now);
+        verifyDelays(now, new long[] {extra, rd2, rd2 + btwn + extra, rd2 + (btwn + extra) * 2});
+        mActiveServices.mRestartingServices.remove(1);
+        mActiveServices.rescheduleServiceRestartIfPossibleLocked(extra, btwn, "test", now);
+        verifyDelays(now, new long[] {extra, btwn + extra * 2, rd4});
+
+        fillInRestartingServices(now, new long[] {rd0, rd1, rd2, rd3, rd4, rd5});
+        setNextRestarts(now, new long[] {extra, btwn + extra * 2, btwn * 2 + extra * 3,
+                btwn * 3 + extra * 4, btwn * 4 + extra * 5, btwn * 5 + extra * 6});
+        mActiveServices.mRestartingServices.remove(1);
+        mActiveServices.rescheduleServiceRestartIfPossibleLocked(extra, btwn, "test", now);
+        memFactor = ADJ_MEM_FACTOR_LOW;
+        extra = mService.mConstants.mExtraServiceRestartDelayOnMemPressure[memFactor];
+        when(mService.mAppProfiler.getLastMemoryLevelLocked()).thenReturn(memFactor);
+        mActiveServices.rescheduleServiceRestartIfPossibleLocked(extra, btwn, "test", now);
+        verifyDelays(now, new long[] {extra, btwn + extra * 2, rd2,
+                rd2 + btwn + extra, rd2 + (btwn + extra) * 2});
+    }
+
+    private void prepareTestRescheduleServiceRestarts() {
+        mService = mock(ActivityManagerService.class);
+        mService.mConstants = mock(ActivityManagerConstants.class);
+        mService.mConstants.mEnableExtraServiceRestartDelayOnMemPressure = true;
+        mService.mConstants.mExtraServiceRestartDelayOnMemPressure =
+                DEFAULT_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
+        mService.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN =
+                DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN;
+        mProfiler = mock(AppProfiler.class);
+        setFieldValue(ActivityManagerService.class, mService, "mAppProfiler", mProfiler);
+        when(mProfiler.getLastMemoryLevelLocked()).thenReturn(ADJ_MEM_FACTOR_NORMAL);
+        mActiveServices = mock(ActiveServices.class);
+        setFieldValue(ActiveServices.class, mActiveServices, "mAm", mService);
+        setFieldValue(ActiveServices.class, mActiveServices, "mRestartingServices",
+                new ArrayList<>());
+        setFieldValue(ActiveServices.class, mActiveServices, "mRestartBackoffDisabledPackages",
+                new ArraySet<>());
+        doNothing().when(mActiveServices).performScheduleRestartLocked(any(ServiceRecord.class),
+                any(String.class), any(String.class), anyLong());
+        doCallRealMethod().when(mActiveServices)
+                .rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                        anyBoolean(), anyBoolean(), anyLong());
+        doCallRealMethod().when(mActiveServices)
+                .rescheduleServiceRestartOnMemoryPressureIfNeededLocked(
+                        anyInt(), anyInt(), any(String.class), anyLong());
+        doCallRealMethod().when(mActiveServices)
+                .rescheduleServiceRestartIfPossibleLocked(
+                        anyLong(), anyLong(), any(String.class), anyLong());
+        doCallRealMethod().when(mActiveServices)
+                .performRescheduleServiceRestartOnMemoryPressureLocked(
+                        anyLong(), anyLong(), any(String.class), anyLong());
+        doCallRealMethod().when(mActiveServices).getExtraRestartTimeInBetweenLocked();
+        doCallRealMethod().when(mActiveServices)
+                .isServiceRestartBackoffEnabledLocked(any(String.class));
+    }
+
+    private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Field mfield = Field.class.getDeclaredField("accessFlags");
+            mfield.setAccessible(true);
+            mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+            field.set(obj, val);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+        }
+    }
+
+    private void fillInRestartingServices(long now, long[] delays) {
+        mActiveServices.mRestartingServices.clear();
+        for (int i = 0; i < delays.length; i++) {
+            mActiveServices.mRestartingServices.add(
+                    createRestartingService("testpackage" + i, now, delays[i]));
+        }
+    }
+
+    private void setNextRestarts(long now, long[] nextRestartDelays) {
+        for (int i = 0; i < nextRestartDelays.length; i++) {
+            final ServiceRecord r = mActiveServices.mRestartingServices.get(i);
+            r.restartDelay = nextRestartDelays[i];
+            r.nextRestartTime = now + r.restartDelay;
+        }
+    }
+
+    private ServiceRecord createRestartingService(String packageName, long now, long delay) {
+        final ServiceRecord r = mock(ServiceRecord.class);
+        r.appInfo = new ApplicationInfo();
+        r.appInfo.flags = delay == 0 ? ApplicationInfo.FLAG_PERSISTENT : 0;
+        final ServiceInfo si = new ServiceInfo();
+        setFieldValue(ServiceRecord.class, r, "serviceInfo", si);
+        setFieldValue(ServiceRecord.class, r, "packageName", packageName);
+        si.applicationInfo = r.appInfo;
+        r.nextRestartTime = r.mEarliestRestartTime = now + delay;
+        r.mRestartSchedulingTime = now;
+        r.restartDelay = delay;
+        return r;
+    }
+
+    private void verifyDelays(long now, long[] delays) throws Exception {
+        for (int i = 0; i < delays.length; i++) {
+            final ServiceRecord r = mActiveServices.mRestartingServices.get(i);
+            assertEquals("Expected restart delay=" + delays[i],
+                    Math.max(0, delays[i]), r.restartDelay);
+            assertEquals("Expected next restart time=" + (now + delays[i]),
+                    now + delays[i], r.nextRestartTime);
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 20a5842..a883293 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -173,8 +173,6 @@
                 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
         assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
                 CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
-        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
-                CachedAppOptimizer.DEFAULT_USE_FREEZER);
         assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo(
                 CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ);
         assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo(
@@ -188,6 +186,10 @@
         }
         assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle)
                 .containsExactlyElementsIn(expected);
+
+        Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+                CachedAppOptimizer.DEFAULT_USE_FREEZER);
     }
 
     @Test
@@ -244,9 +246,8 @@
                     CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10), false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
-        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
-                CachedAppOptimizer.DEFAULT_USE_FREEZER);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                 CachedAppOptimizer.KEY_USE_FREEZER, CachedAppOptimizer.DEFAULT_USE_FREEZER
                         ? "false" : "true", false);
 
@@ -291,7 +292,8 @@
                 CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1);
         assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).containsExactly(1, 2, 3);
 
-        if (mCachedAppOptimizerUnderTest.isFreezerSupported()) {
+        Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
+        if (CachedAppOptimizer.isFreezerSupported()) {
             if (CachedAppOptimizer.DEFAULT_USE_FREEZER) {
                 assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
             } else {
@@ -325,15 +327,15 @@
 
     @Test
     public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException {
-        Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
+        Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
 
-        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
-                CachedAppOptimizer.DEFAULT_USE_FREEZER);
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
 
         // The freezer DeviceConfig property is read at boot only
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                 CachedAppOptimizer.KEY_USE_FREEZER, "true", false);
         mCachedAppOptimizerUnderTest.init();
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
         mCountDown = new CountDownLatch(1);
 
         // No notifications should get to the cached app optimizer.
@@ -346,14 +348,13 @@
 
         // Set the flag the other way without rebooting. It shall not change.
         mCountDown = new CountDownLatch(1);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                 CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
         assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
         assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
 
-
         // Now, set the flag to false and restart the cached app optimizer
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                 CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
         mCachedAppOptimizerUnderTest.init();
 
@@ -380,18 +381,17 @@
 
     @Test
     public void useFreeze_listensToDeviceConfigChangesBadValues() throws InterruptedException {
-        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
-                CachedAppOptimizer.DEFAULT_USE_FREEZER);
+        Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
 
         // When we push an invalid flag value...
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
                 CachedAppOptimizer.KEY_USE_FREEZER, "foobar", false);
 
         mCachedAppOptimizerUnderTest.init();
 
-        // Then we set the default.
-        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
-                CachedAppOptimizer.DEFAULT_USE_FREEZER);
+        // DeviceConfig treats invalid value as false
+        assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
index 589a349..457c8db 100644
--- a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
@@ -48,7 +48,7 @@
 import org.mockito.quality.Strictness;
 
 /**
- * Run it as {@code atest FrameworksMockingCoreTests:FactoryResetterTest}
+ * Run it as {@code atest FrameworksMockingServicesTests:FactoryResetterTest}
  */
 @Presubmit
 public final class FactoryResetterTest {
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java
new file mode 100644
index 0000000..dd67d72
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import static android.os.UserHandle.USER_NULL;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.testng.Assert.expectThrows;
+
+import android.content.ComponentName;
+
+import org.junit.Test;
+
+/**
+ * Run it as {@code atest FrameworksMockingServicesTests:OwnerShellDataTest}
+ */
+public final class OwnerShellDataTest {
+
+    private static final int USER_ID = 007;
+    private static final int PARENT_USER_ID = 'M' + 'I' + 6;
+    private static final ComponentName ADMIN = new ComponentName("Bond", "James");
+
+    @Test
+    public void testForDeviceOwner_noAdmin() {
+        expectThrows(NullPointerException.class,
+                () -> OwnerShellData.forDeviceOwner(USER_ID, /* admin= */ null));
+    }
+
+    @Test
+    public void testForDeviceOwner_invalidUser() {
+        expectThrows(IllegalArgumentException.class,
+                () -> OwnerShellData.forDeviceOwner(USER_NULL, ADMIN));
+    }
+
+    @Test
+    public void testForDeviceOwner() {
+        OwnerShellData dto = OwnerShellData.forDeviceOwner(USER_ID, ADMIN);
+
+        assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+        assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+                .isEqualTo(USER_NULL);
+        assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+        assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isTrue();
+        assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isFalse();
+        assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+                .isFalse();
+        assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+    }
+
+    @Test
+    public void testForUserProfileOwner_noAdmin() {
+        expectThrows(NullPointerException.class,
+                () -> OwnerShellData.forUserProfileOwner(USER_ID, /* admin= */ null));
+    }
+
+    @Test
+    public void testForUserProfileOwner_invalidUser() {
+        expectThrows(IllegalArgumentException.class,
+                () -> OwnerShellData.forUserProfileOwner(USER_NULL, ADMIN));
+    }
+
+    @Test
+    public void testForUserProfileOwner() {
+        OwnerShellData dto = OwnerShellData.forUserProfileOwner(USER_ID, ADMIN);
+
+        assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+        assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+                .isEqualTo(USER_NULL);
+        assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+        assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isFalse();
+        assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isTrue();
+        assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+                .isFalse();
+        assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+    }
+
+    @Test
+    public void testForManagedProfileOwner_noAdmin() {
+        expectThrows(NullPointerException.class,
+                () -> OwnerShellData.forManagedProfileOwner(USER_ID, PARENT_USER_ID, null));
+    }
+
+    @Test
+    public void testForManagedProfileOwner_invalidUser() {
+        expectThrows(IllegalArgumentException.class,
+                () -> OwnerShellData.forManagedProfileOwner(USER_NULL, PARENT_USER_ID, ADMIN));
+    }
+
+    @Test
+    public void testForManagedProfileOwner_invalidParent() {
+        expectThrows(IllegalArgumentException.class,
+                () -> OwnerShellData.forManagedProfileOwner(USER_ID, USER_NULL, ADMIN));
+    }
+
+    @Test
+    public void testForManagedProfileOwner_parentOfItself() {
+        expectThrows(IllegalArgumentException.class,
+                () -> OwnerShellData.forManagedProfileOwner(USER_ID, USER_ID, ADMIN));
+    }
+
+    @Test
+    public void testForManagedProfileOwner() {
+        OwnerShellData dto = OwnerShellData.forManagedProfileOwner(USER_ID, PARENT_USER_ID, ADMIN);
+
+        assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+        assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+                .isEqualTo(PARENT_USER_ID);
+        assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+        assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isFalse();
+        assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isFalse();
+        assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+                .isTrue();
+        assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 0efcc57..34856e2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -134,6 +134,14 @@
         when(mMockedResources.getFloat(com.android.internal.R.dimen
                 .config_screenBrightnessSettingMaximumFloat))
                 .thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[1]);
+        when(mMockedResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{});
+        TypedArray mockArray = mock(TypedArray.class);
+        when(mockArray.length()).thenReturn(0);
+        when(mMockedResources.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray))
+                .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_waterfallCutoutArray))
+                .thenReturn(mockArray);
     }
 
     @After
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 697451e..a94f0ee 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -881,6 +881,7 @@
         //   * E jobs test that expedited jobs don't skip the line when the app has no regular jobs
         //   * F jobs test correct expedited/regular ordering doesn't push jobs too high in list
         //   * G jobs test correct ordering for regular jobs
+        //   * H job tests correct behavior when enqueue times are the same
         JobStatus rA1 = createJobStatus("testPendingJobSorting", createJobInfo(1), 1);
         JobStatus rB2 = createJobStatus("testPendingJobSorting", createJobInfo(2), 2);
         JobStatus eC3 = createJobStatus("testPendingJobSorting",
@@ -892,6 +893,7 @@
                 createJobInfo(6).setExpedited(true), 2);
         JobStatus eA7 = createJobStatus("testPendingJobSorting",
                 createJobInfo(7).setExpedited(true), 1);
+        JobStatus rH8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 14);
         JobStatus rF8 = createJobStatus("testPendingJobSorting", createJobInfo(8), 6);
         JobStatus eF9 = createJobStatus("testPendingJobSorting",
                 createJobInfo(9).setExpedited(true), 6);
@@ -911,6 +913,7 @@
         eB6.enqueueTime = 6;
         eA7.enqueueTime = 7;
         rF8.enqueueTime = 8;
+        rH8.enqueueTime = 8;
         eF9.enqueueTime = 9;
         rC10.enqueueTime = 10;
         eC11.enqueueTime = 11;
@@ -927,6 +930,7 @@
         mService.mPendingJobs.add(rD4);
         mService.mPendingJobs.add(eA7);
         mService.mPendingJobs.add(rG12);
+        mService.mPendingJobs.add(rH8);
         mService.mPendingJobs.add(rF8);
         mService.mPendingJobs.add(eB6);
         mService.mPendingJobs.add(eE14);
@@ -939,7 +943,7 @@
         mService.mPendingJobs.sort(mService.mPendingJobComparator);
 
         final JobStatus[] expectedOrder = new JobStatus[]{
-                eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rF8, eC11, rC10, rG12, rG13, eE14};
+                eA7, rA1, eB6, rB2, eC3, rD4, eE5, eF9, rH8, rF8, eC11, rC10, rG12, rG13, eE14};
         for (int i = 0; i < expectedOrder.length; ++i) {
             assertEquals("List wasn't correctly sorted @ index " + i,
                     expectedOrder[i].getJobId(), mService.mPendingJobs.get(i).getJobId());
@@ -991,7 +995,7 @@
         for (int i = 0; i < 2500; ++i) {
             JobStatus job = createJobStatus("testPendingJobSorting_Random",
                     createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(250));
-            job.enqueueTime = Math.abs(random.nextInt(1_000_000));
+            job.enqueueTime = random.nextInt(1_000_000);
             mService.mPendingJobs.add(job);
 
             mService.mPendingJobComparator.refreshLocked();
@@ -1019,18 +1023,48 @@
 
     @Test
     public void testPendingJobSortingTransitivity() {
-        Random random = new Random(1); // Always use the same series of pseudo random values.
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 7357, 606, 6357, 41106010, 3, 2, 1}) {
+            Random random = new Random(seed);
 
-        mService.mPendingJobs.clear();
+            mService.mPendingJobs.clear();
 
-        for (int i = 0; i < 250; ++i) {
-            JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
-                    createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
-            job.enqueueTime = Math.abs(random.nextInt(1_000_000));
-            job.overrideState = random.nextInt(4);
-            mService.mPendingJobs.add(job);
+            for (int i = 0; i < 300; ++i) {
+                JobStatus job = createJobStatus("testPendingJobSortingTransitivity",
+                        createJobInfo(i).setExpedited(random.nextBoolean()), random.nextInt(50));
+                job.enqueueTime = random.nextInt(1_000_000);
+                job.overrideState = random.nextInt(4);
+                mService.mPendingJobs.add(job);
+            }
+
+            verifyPendingJobComparatorTransitivity();
         }
+    }
 
+    @Test
+    public void testPendingJobSortingTransitivity_Concentrated() {
+        // Always use the same series of pseudo random values.
+        for (int seed : new int[]{1337, 6000, 637739, 6357, 1, 7, 13}) {
+            Random random = new Random(seed);
+
+            mService.mPendingJobs.clear();
+
+            for (int i = 0; i < 300; ++i) {
+                JobStatus job = createJobStatus("testPendingJobSortingTransitivity_Concentrated",
+                        createJobInfo(i).setExpedited(random.nextFloat() < .03),
+                        random.nextInt(20));
+                job.enqueueTime = random.nextInt(250);
+                job.overrideState = random.nextFloat() < .01
+                        ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_NONE;
+                mService.mPendingJobs.add(job);
+                Log.d(TAG, sortedJobToString(job));
+            }
+
+            verifyPendingJobComparatorTransitivity();
+        }
+    }
+
+    private void verifyPendingJobComparatorTransitivity() {
         mService.mPendingJobComparator.refreshLocked();
 
         for (int i = 0; i < mService.mPendingJobs.size(); ++i) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
new file mode 100644
index 0000000..f94377f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.power;
+
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import static com.android.server.power.ScreenUndimDetector.DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_KEEP_SCREEN_ON_ENABLED;
+import static com.android.server.power.ScreenUndimDetector.KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS;
+import static com.android.server.power.ScreenUndimDetector.KEY_UNDIMS_REQUIRED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.testing.TestableContext;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.testables.TestableDeviceConfig;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.server.power.ScreenUndimDetector}
+ */
+@RunWith(JUnit4.class)
+public class ScreenUndimDetectorTest {
+    private static final List<Integer> ALL_POLICIES =
+            Arrays.asList(POLICY_OFF,
+                    POLICY_DOZE,
+                    POLICY_DIM,
+                    POLICY_BRIGHT,
+                    POLICY_VR);
+
+    @ClassRule
+    public static final TestableContext sContext = new TestableContext(
+            InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+    @Rule
+    public TestableDeviceConfig.TestableDeviceConfigRule
+            mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+    private ScreenUndimDetector mScreenUndimDetector;
+
+    private final TestClock mClock = new TestClock();
+
+    private static class TestClock extends ScreenUndimDetector.InternalClock {
+        long mCurrentTime = 0;
+        @Override
+        public long getCurrentTime() {
+            return mCurrentTime;
+        }
+
+        public void advanceTime(long millisAdvanced) {
+            mCurrentTime += millisAdvanced;
+        }
+    }
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(1), false /*makeDefault*/);
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_MAX_DURATION_BETWEEN_UNDIMS_MILLIS,
+                Long.toString(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS),
+                false /*makeDefault*/);
+
+        mScreenUndimDetector = new ScreenUndimDetector(mClock);
+        mScreenUndimDetector.systemReady(sContext);
+    }
+
+    @Test
+    public void recordScreenPolicy_disabledByFlag_noop() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_KEEP_SCREEN_ON_ENABLED, Boolean.FALSE.toString(), false /*makeDefault*/);
+
+        setup();
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+    }
+
+    @Test
+    public void recordScreenPolicy_samePolicy_noop() {
+        for (int policy : ALL_POLICIES) {
+            setup();
+            mScreenUndimDetector.recordScreenPolicy(policy);
+            mScreenUndimDetector.recordScreenPolicy(policy);
+
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_extends() {
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+    }
+
+    @Test
+    public void recordScreenPolicy_otherTransitions_doesNotExtend() {
+        for (int from : ALL_POLICIES) {
+            for (int to : ALL_POLICIES) {
+                if (from == POLICY_DIM && to == POLICY_BRIGHT) {
+                    continue;
+                }
+                setup();
+                mScreenUndimDetector.recordScreenPolicy(from);
+                mScreenUndimDetector.recordScreenPolicy(to);
+
+                assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+                assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            }
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_twoUndimsNeeded_extends() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isTrue();
+    }
+
+    @Test
+    public void recordScreenPolicy_dimBrightDimOff_resetsCounter_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+    }
+
+    @Test
+    public void recordScreenPolicy_undimToOff_resetsCounter() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+    }
+
+    @Test
+    public void recordScreenPolicy_undimOffUndim_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        // undim
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        // off
+        mScreenUndimDetector.recordScreenPolicy(POLICY_OFF);
+        // second undim
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToBright_tooFarApart_doesNotExtend() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(2), false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        mClock.advanceTime(DEFAULT_MAX_DURATION_BETWEEN_UNDIMS_MILLIS + 5);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+        mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+
+        assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(1);
+    }
+
+    @Test
+    public void recordScreenPolicy_dimToNonBright_resets() {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+            setup();
+            mScreenUndimDetector.mUndimCounter = 1;
+            mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+            mScreenUndimDetector.mWakeLock.acquire();
+
+            mScreenUndimDetector.recordScreenPolicy(POLICY_DIM);
+            mScreenUndimDetector.recordScreenPolicy(to);
+
+            assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+
+    }
+
+    @Test
+    public void recordScreenPolicy_brightToNonDim_resets() {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+            setup();
+            mScreenUndimDetector.mUndimCounter = 1;
+            mScreenUndimDetector.mUndimCounterStartedMillis = 123;
+            mScreenUndimDetector.mWakeLock.acquire();
+
+            mScreenUndimDetector.recordScreenPolicy(POLICY_BRIGHT);
+            mScreenUndimDetector.recordScreenPolicy(to);
+
+            assertThat(mScreenUndimDetector.mUndimCounter).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isEqualTo(0);
+            assertThat(mScreenUndimDetector.mWakeLock.isHeld()).isFalse();
+        }
+    }
+
+    @Test
+    public void recordScreenPolicy_otherTransitions_doesNotReset() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_UNDIMS_REQUIRED,
+                Integer.toString(3),
+                false /*makeDefault*/);
+        mScreenUndimDetector.readValuesFromDeviceConfig();
+
+        for (int from : ALL_POLICIES) {
+            for (int to : ALL_POLICIES) {
+                if (from == POLICY_DIM && to != POLICY_BRIGHT) {
+                    continue;
+                }
+                if (from == POLICY_BRIGHT && to != POLICY_DIM) {
+                    continue;
+                }
+                mScreenUndimDetector.mCurrentScreenPolicy = POLICY_OFF;
+                mScreenUndimDetector.mUndimCounter = 1;
+                mScreenUndimDetector.mUndimCounterStartedMillis =
+                        SystemClock.currentThreadTimeMillis();
+
+                mScreenUndimDetector.recordScreenPolicy(from);
+                mScreenUndimDetector.recordScreenPolicy(to);
+
+                assertThat(mScreenUndimDetector.mUndimCounter).isNotEqualTo(0);
+                assertThat(mScreenUndimDetector.mUndimCounterStartedMillis).isNotEqualTo(0);
+            }
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
index 10f4c05..9dd413b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ServiceRestarterTest.java
@@ -16,6 +16,10 @@
 
 package com.android.server.am;
 
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -28,6 +32,9 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.os.SystemClock;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.server.wm.settings.SettingsSession;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
@@ -36,6 +43,7 @@
 
 import com.android.compatibility.common.util.SystemUtil;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -59,6 +67,12 @@
             "com.android.servicestests.apps.simpleservicetestapp3";
     private static final String TEST_SERVICE_NAME =
             "com.android.servicestests.apps.simpleservicetestapp.SimpleService";
+    private static final String[] MEMORY_PRESSURE_MAP = {
+            "NORMAL", "MODERATE", "LOW", "CRITICAL"};
+    private static final String EXTRA_DELAY = "0,2000,4000,8000";
+    private static final int SERVICE_RESTART_DURATION_FACTOR = 2;
+    private static final long BOUND_SERVICE_CRASH_RESTART_DURATION = 1000;
+    private static final long SERVICE_MIN_RESTART_TIME_BETWEEN = 1000;
 
     private static final long WAIT_MS = 5 * 1000;
     private static final long WAIT_LONG_MS = 30 * 1000;
@@ -69,6 +83,10 @@
     private static final int ACTION_STOPPKG = 8;
     private static final int ACTION_ALL = ACTION_START | ACTION_KILL | ACTION_WAIT | ACTION_STOPPKG;
 
+    private SettingsSession<String> mAMConstantsSettings;
+    private DeviceConfigSession<String> mExtraDelaysDeviceConfig;
+    private DeviceConfigSession<Boolean> mEnableExtraDelaysDeviceConfig;
+
     private Context mContext;
     private Instrumentation mInstrumentation;
     private int mTestPackage1Uid;
@@ -85,6 +103,40 @@
         mTestPackage2Uid = ai.uid;
         ai = mContext.getPackageManager().getApplicationInfo(TEST_PACKAGE3_NAME, 0);
         mTestPackage3Uid = ai.uid;
+        final String activityManagerConstants = Settings.Global.ACTIVITY_MANAGER_CONSTANTS;
+        mAMConstantsSettings = new SettingsSession<>(
+                Settings.Global.getUriFor(activityManagerConstants),
+                Settings.Global::getString, Settings.Global::putString);
+        mAMConstantsSettings.set(
+                ActivityManagerConstants.KEY_SERVICE_RESTART_DURATION_FACTOR + "="
+                + SERVICE_RESTART_DURATION_FACTOR + ","
+                + ActivityManagerConstants.KEY_BOUND_SERVICE_CRASH_RESTART_DURATION + "="
+                + BOUND_SERVICE_CRASH_RESTART_DURATION + ","
+                + ActivityManagerConstants.KEY_SERVICE_MIN_RESTART_TIME_BETWEEN + "="
+                + SERVICE_MIN_RESTART_TIME_BETWEEN);
+        mExtraDelaysDeviceConfig = new DeviceConfigSession<>(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                ActivityManagerConstants.KEY_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE,
+                DeviceConfig::getString, null);
+        mExtraDelaysDeviceConfig.set(EXTRA_DELAY);
+        mEnableExtraDelaysDeviceConfig = new DeviceConfigSession<>(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                ActivityManagerConstants.KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE,
+                DeviceConfig::getBoolean, false);
+        mEnableExtraDelaysDeviceConfig.set(true);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mAMConstantsSettings != null) {
+            mAMConstantsSettings.close();
+        }
+        if (mExtraDelaysDeviceConfig != null) {
+            mExtraDelaysDeviceConfig.close();
+        }
+        if (mEnableExtraDelaysDeviceConfig != null) {
+            mEnableExtraDelaysDeviceConfig.close();
+        }
     }
 
     @LargeTest
@@ -113,7 +165,7 @@
             // Test restarts in normal case
             final long[] ts1 = startKillAndRestart(am, ACTION_START | ACTION_KILL | ACTION_WAIT,
                     uid1Listener1, uid1Listener2, uid2Listener1, uid2Listener2,
-                    uid3Listener1, uid3Listener2, Long.MAX_VALUE);
+                    uid3Listener1, uid3Listener2, Long.MAX_VALUE, false);
             assertTrue("app1 restart should be before app2", ts1[1] < ts1[2]);
             assertTrue("app2 restart should be before app3", ts1[2] < ts1[3]);
 
@@ -122,7 +174,7 @@
             // Test restarts again.
             final long[] ts2 = startKillAndRestart(am, ACTION_KILL | ACTION_WAIT | ACTION_STOPPKG,
                     uid1Listener1, uid1Listener2, uid2Listener1,
-                    uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE);
+                    uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE, false);
             assertTrue("app2 restart should be before app1", ts2[2] < ts2[1]);
             assertTrue("app1 restart should be before app3", ts2[1] < ts2[3]);
             assertTrue("app2 should be restart in a very short moment", ts2[2] - ts2[0] < WAIT_MS);
@@ -131,7 +183,8 @@
             executeShellCmd("am service-restart-backoff enable " + TEST_PACKAGE2_NAME);
             // Test restarts again.
             final long[] ts3 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2,
-                    uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE);
+                    uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, Long.MAX_VALUE,
+                    false);
             assertTrue("app1 restart should be before app2", ts3[1] < ts3[2]);
             assertTrue("app2 restart should be before app3", ts3[2] < ts3[3]);
 
@@ -152,11 +205,101 @@
         }
     }
 
+    @LargeTest
+    @Test
+    public void testExtraDelaysInServiceRestartOnLowMem() throws Exception {
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final MyUidImportanceListener uid1Listener1 = new MyUidImportanceListener(mTestPackage1Uid);
+        final MyUidImportanceListener uid1Listener2 = new MyUidImportanceListener(mTestPackage1Uid);
+        final MyUidImportanceListener uid2Listener1 = new MyUidImportanceListener(mTestPackage2Uid);
+        final MyUidImportanceListener uid2Listener2 = new MyUidImportanceListener(mTestPackage2Uid);
+        final MyUidImportanceListener uid3Listener1 = new MyUidImportanceListener(mTestPackage3Uid);
+        final MyUidImportanceListener uid3Listener2 = new MyUidImportanceListener(mTestPackage3Uid);
+        try {
+            am.addOnUidImportanceListener(uid1Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
+            am.addOnUidImportanceListener(uid1Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+            am.addOnUidImportanceListener(uid2Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
+            am.addOnUidImportanceListener(uid2Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+            am.addOnUidImportanceListener(uid3Listener1, RunningAppProcessInfo.IMPORTANCE_SERVICE);
+            am.addOnUidImportanceListener(uid3Listener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+            executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE1_NAME);
+            executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE2_NAME);
+            executeShellCmd("cmd deviceidle whitelist +" + TEST_PACKAGE3_NAME);
+
+            // Force the memory pressure to normal.
+            setMemoryPressure(ADJ_MEM_FACTOR_NORMAL);
+
+            // Test restarts in normal condition.
+            final long[] ts1 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2,
+                    uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true);
+
+            // Mimic a memory pressure event.
+            setMemoryPressure(ADJ_MEM_FACTOR_MODERATE);
+
+            final long[] ts2 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2,
+                    uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true);
+
+            assertTrue("Expect extra delays in service restarts",
+                    (ts2[1] - ts2[0]) > (ts1[1] - ts1[0]));
+            assertTrue("Expect extra delays in service restarts",
+                    (ts2[2] - ts2[0]) > (ts1[2] - ts1[0]));
+            assertTrue("Expect extra delays in service restarts",
+                    (ts2[3] - ts2[0]) > (ts1[3] - ts1[0]));
+
+            // Increase the memory pressure event.
+            setMemoryPressure(ADJ_MEM_FACTOR_LOW);
+
+            final long[] ts3 = startKillAndRestart(am, ACTION_ALL, uid1Listener1, uid1Listener2,
+                    uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2, WAIT_LONG_MS, true);
+
+            assertTrue("Expect extra delays in service restarts",
+                    (ts3[1] - ts3[0]) > (ts2[1] - ts2[0]));
+            assertTrue("Expect extra delays in service restarts",
+                    (ts3[2] - ts3[0]) > (ts2[2] - ts2[0]));
+            assertTrue("Expect extra delays in service restarts",
+                    (ts3[3] - ts3[0]) > (ts2[3] - ts2[0]));
+
+            // Start and kill them again, but don't wait for the restart.
+            final long now4 = startKillAndRestart(am, ACTION_START | ACTION_KILL, uid1Listener1,
+                    uid1Listener2, uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2,
+                    WAIT_LONG_MS, true)[0];
+
+            // Set the memory pressure to normal.
+            setMemoryPressure(ADJ_MEM_FACTOR_NORMAL);
+
+            // Now wait for the restarts.
+            final long[] ts4 = startKillAndRestart(am, ACTION_WAIT | ACTION_STOPPKG, uid1Listener1,
+                    uid1Listener2, uid2Listener1, uid2Listener2, uid3Listener1, uid3Listener2,
+                    WAIT_LONG_MS, true);
+
+            assertTrue("Expect less delays in service restarts",
+                    (ts4[1] - now4) < (ts2[1] - ts2[0]));
+            assertTrue("Expect less delays in service restarts",
+                    (ts4[2] - now4) < (ts2[2] - ts2[0]));
+            assertTrue("Expect less delays in service restarts",
+                    (ts4[3] - now4) < (ts2[3] - ts2[0]));
+        } finally {
+            executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE1_NAME);
+            executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE2_NAME);
+            executeShellCmd("cmd deviceidle whitelist -" + TEST_PACKAGE3_NAME);
+            resetMemoryPressure();
+            am.removeOnUidImportanceListener(uid1Listener1);
+            am.removeOnUidImportanceListener(uid1Listener2);
+            am.removeOnUidImportanceListener(uid2Listener1);
+            am.removeOnUidImportanceListener(uid2Listener2);
+            am.removeOnUidImportanceListener(uid3Listener1);
+            am.removeOnUidImportanceListener(uid3Listener2);
+            am.forceStopPackage(TEST_PACKAGE1_NAME);
+            am.forceStopPackage(TEST_PACKAGE2_NAME);
+            am.forceStopPackage(TEST_PACKAGE3_NAME);
+        }
+    }
+
     private long[] startKillAndRestart(ActivityManager am, int action,
             MyUidImportanceListener uid1Listener1, MyUidImportanceListener uid1Listener2,
             MyUidImportanceListener uid2Listener1, MyUidImportanceListener uid2Listener2,
             MyUidImportanceListener uid3Listener1, MyUidImportanceListener uid3Listener2,
-            long waitDuration) throws Exception {
+            long waitDuration, boolean checkStartSeq) throws Exception {
         final long[] res = new long[4];
         // Test restarts in normal condition.
         if ((action & ACTION_START) != 0) {
@@ -179,9 +322,15 @@
                     RunningAppProcessInfo.IMPORTANCE_SERVICE, waitDuration));
             assertTrue("Timed out to restart " + TEST_PACKAGE3_NAME, uid3Listener1.waitFor(
                     RunningAppProcessInfo.IMPORTANCE_SERVICE, waitDuration));
-            res[1] = uid1Listener1.mCurrentTimestamp;
-            res[2] = uid2Listener1.mCurrentTimestamp;
-            res[3] = uid3Listener1.mCurrentTimestamp;
+            final long uid1RestartTime = res[1] = uid1Listener1.mCurrentTimestamp;
+            final long uid2RestartTime = res[2] = uid2Listener1.mCurrentTimestamp;
+            final long uid3RestartTime = res[3] = uid3Listener1.mCurrentTimestamp;
+            if (checkStartSeq) {
+                assertTrue(TEST_PACKAGE1_NAME + " should restart before " + TEST_PACKAGE2_NAME,
+                        uid1RestartTime <= uid2RestartTime);
+                assertTrue(TEST_PACKAGE2_NAME + " should restart before " + TEST_PACKAGE3_NAME,
+                        uid2RestartTime <= uid3RestartTime);
+            }
         }
 
         if ((action & ACTION_STOPPKG) != 0) {
@@ -224,6 +373,14 @@
         return result;
     }
 
+    private void setMemoryPressure(int pressure) throws Exception {
+        executeShellCmd("am memory-factor set " + MEMORY_PRESSURE_MAP[pressure]);
+    }
+
+    private void resetMemoryPressure() throws Exception {
+        executeShellCmd("am memory-factor reset");
+    }
+
     private static class MyUidImportanceListener implements OnUidImportanceListener {
         final CountDownLatch[] mLatchHolder = new CountDownLatch[1];
         private final int mExpectedUid;
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
index c12eb32..e98a4dd 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -64,12 +64,16 @@
                 .times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
         inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
                 .times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
 
         // Stop watching
         appOpsManager.stopWatchingStarted(listener);
@@ -94,7 +98,9 @@
                 .times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
         verifyNoMoreInteractions(listener);
 
         // Finish up
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 8592166a..f4d1499 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -378,6 +378,11 @@
         protected void handleLifecycleAfterAuth(boolean authenticated) {
 
         }
+
+        @Override
+        public boolean wasUserDetected() {
+            return false;
+        }
     }
 
     private static class TestAuthenticationClient extends AuthenticationClient<Object> {
@@ -407,6 +412,11 @@
         protected void handleLifecycleAfterAuth(boolean authenticated) {
 
         }
+
+        @Override
+        public boolean wasUserDetected() {
+            return false;
+        }
     }
 
     private static class TestClientMonitor2 extends TestClientMonitor {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index f1adcae..bfb0be7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.withSettings;
 
 import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
 import android.os.Handler;
 import android.os.Looper;
 import android.platform.test.annotations.Presubmit;
@@ -61,6 +62,8 @@
     private Context mContext;
     @Mock
     private CoexCoordinator.Callback mCallback;
+    @Mock
+    private CoexCoordinator.ErrorCallback mErrorCallback;
 
     @Before
     public void setUp() {
@@ -70,6 +73,7 @@
 
         mCoexCoordinator = CoexCoordinator.getInstance();
         mCoexCoordinator.setAdvancedLogicEnabled(true);
+        mCoexCoordinator.setFaceHapticDisabledWhenNonBypass(true);
     }
 
     @Test
@@ -151,12 +155,76 @@
 
         mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
                 mCallback);
-        verify(mCallback).sendHapticFeedback();
+        // Haptics tested in #testKeyguard_bypass_haptics. Let's leave this commented out (instead
+        // of removed) to keep this context.
+        // verify(mCallback).sendHapticFeedback();
         verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
         verify(mCallback).handleLifecycleAfterAuth();
     }
 
     @Test
+    public void testKeyguard_faceAuthSuccess_nonBypass_udfpsRunning_noHaptics() {
+        testKeyguard_bypass_haptics(false /* bypassEnabled */,
+                true /* faceAccepted */,
+                false /* shouldReceiveHaptics */);
+    }
+
+    @Test
+    public void testKeyguard_faceAuthReject_nonBypass_udfpsRunning_noHaptics() {
+        testKeyguard_bypass_haptics(false /* bypassEnabled */,
+                false /* faceAccepted */,
+                false /* shouldReceiveHaptics */);
+    }
+
+    @Test
+    public void testKeyguard_faceAuthSuccess_bypass_udfpsRunning_haptics() {
+        testKeyguard_bypass_haptics(true /* bypassEnabled */,
+                true /* faceAccepted */,
+                true /* shouldReceiveHaptics */);
+    }
+
+    @Test
+    public void testKeyguard_faceAuthReject_bypass_udfpsRunning_haptics() {
+        testKeyguard_bypass_haptics(true /* bypassEnabled */,
+                false /* faceAccepted */,
+                true /* shouldReceiveHaptics */);
+    }
+
+    private void testKeyguard_bypass_haptics(boolean bypassEnabled, boolean faceAccepted,
+            boolean shouldReceiveHaptics) {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+        when(faceClient.isKeyguard()).thenReturn(true);
+        when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+
+        AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+                withSettings().extraInterfaces(Udfps.class));
+        when(udfpsClient.isKeyguard()).thenReturn(true);
+        when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+        if (faceAccepted) {
+            mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+                    mCallback);
+        } else {
+            mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+                    LockoutTracker.LOCKOUT_NONE, mCallback);
+        }
+
+        if (shouldReceiveHaptics) {
+            verify(mCallback).sendHapticFeedback();
+        } else {
+            verify(mCallback, never()).sendHapticFeedback();
+        }
+
+        verify(mCallback).sendAuthenticationResult(eq(faceAccepted) /* addAuthTokenIfStrong */);
+        verify(mCallback).handleLifecycleAfterAuth();
+    }
+
+    @Test
     public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedWithinBounds() {
         testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
                 0 /* udfpsRejectedAfterMs */);
@@ -190,13 +258,16 @@
         mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
         mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
 
+        // For easier reading
+        final CoexCoordinator.Callback faceCallback = mCallback;
+
         mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
-                mCallback);
-        verify(mCallback, never()).sendHapticFeedback();
-        verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+                faceCallback);
+        verify(faceCallback, never()).sendHapticFeedback();
+        verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
         // CoexCoordinator requests the system to hold onto this AuthenticationClient until
         // UDFPS result is known
-        verify(mCallback, never()).handleLifecycleAfterAuth();
+        verify(faceCallback, never()).handleLifecycleAfterAuth();
 
         // Reset the mock
         CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
@@ -209,6 +280,8 @@
             verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
             verify(udfpsCallback).handleLifecycleAfterAuth();
 
+            verify(faceCallback).sendAuthenticationCanceled();
+
             assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
         } else {
             mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
@@ -216,16 +289,16 @@
             if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
                 verify(udfpsCallback, never()).sendHapticFeedback();
 
-                verify(mCallback).sendHapticFeedback();
-                verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-                verify(mCallback).handleLifecycleAfterAuth();
+                verify(faceCallback).sendHapticFeedback();
+                verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+                verify(faceCallback).handleLifecycleAfterAuth();
 
                 assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
             } else {
                 assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
 
-                verify(mCallback, never()).sendHapticFeedback();
-                verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+                verify(faceCallback, never()).sendHapticFeedback();
+                verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
 
                 verify(udfpsCallback).sendHapticFeedback();
                 verify(udfpsCallback)
@@ -294,12 +367,13 @@
     }
 
     @Test
-    public void testKeyguard_udfpsRejected_thenFaceRejected() {
+    public void testKeyguard_udfpsRejected_thenFaceRejected_noKeyguardBypass() {
         mCoexCoordinator.reset();
 
         AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
         when(faceClient.isKeyguard()).thenReturn(true);
         when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+        when(faceClient.isKeyguardBypassEnabled()).thenReturn(false); // TODO: also test "true" case
 
         AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
                 withSettings().extraInterfaces(Udfps.class));
@@ -312,8 +386,9 @@
 
         mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, udfpsClient,
                 LockoutTracker.LOCKOUT_NONE, mCallback);
-        // Client becomes paused, but finger does not necessarily lift, since we suppress the haptic
-        when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED_PAUSED);
+        // Auth was attempted
+        when(udfpsClient.getState())
+                .thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED);
         verify(mCallback, never()).sendHapticFeedback();
         verify(mCallback).handleLifecycleAfterAuth();
 
@@ -418,4 +493,82 @@
         verify(callback).handleLifecycleAfterAuth();
         verify(successfulAuths).remove(eq(auth));
     }
+
+    @Test
+    public void testBiometricPrompt_FaceError() {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> client = mock(AuthenticationClient.class);
+        when(client.isBiometricPrompt()).thenReturn(true);
+        when(client.wasAuthAttempted()).thenReturn(true);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+        mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                mErrorCallback);
+        verify(mErrorCallback).sendHapticFeedback();
+    }
+
+    @Test
+    public void testKeyguard_faceAuthOnly_errorWhenBypassEnabled() {
+        testKeyguard_faceAuthOnly(true /* bypassEnabled */);
+    }
+
+    @Test
+    public void testKeyguard_faceAuthOnly_errorWhenBypassDisabled() {
+        testKeyguard_faceAuthOnly(false /* bypassEnabled */);
+    }
+
+    private void testKeyguard_faceAuthOnly(boolean bypassEnabled) {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> client = mock(AuthenticationClient.class);
+        when(client.isKeyguard()).thenReturn(true);
+        when(client.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+        when(client.wasAuthAttempted()).thenReturn(true);
+        when(client.wasUserDetected()).thenReturn(true);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+        mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                mErrorCallback);
+        verify(mErrorCallback).sendHapticFeedback();
+    }
+
+    @Test
+    public void testKeyguard_coex_faceErrorWhenBypassEnabled() {
+        testKeyguard_coex_faceError(true /* bypassEnabled */);
+    }
+
+    @Test
+    public void testKeyguard_coex_faceErrorWhenBypassDisabled() {
+        testKeyguard_coex_faceError(false /* bypassEnabled */);
+    }
+
+    private void testKeyguard_coex_faceError(boolean bypassEnabled) {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+        when(faceClient.isKeyguard()).thenReturn(true);
+        when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+        when(faceClient.wasAuthAttempted()).thenReturn(true);
+        when(faceClient.wasUserDetected()).thenReturn(true);
+
+        AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+                withSettings().extraInterfaces(Udfps.class));
+        when(udfpsClient.isKeyguard()).thenReturn(true);
+        when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+        mCoexCoordinator.onAuthenticationError(faceClient,
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
+
+        if (bypassEnabled) {
+            verify(mErrorCallback).sendHapticFeedback();
+        } else {
+            verify(mErrorCallback, never()).sendHapticFeedback();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index a205a1d..1ac28ab 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -1340,11 +1340,19 @@
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
         director.start(createMockSensorManager());
 
-        ArgumentCaptor<ProximityActiveListener> captor =
+        ArgumentCaptor<ProximityActiveListener> ProximityCaptor =
                 ArgumentCaptor.forClass(ProximityActiveListener.class);
         verify(mSensorManagerInternalMock).addProximityActiveListener(any(Executor.class),
-                captor.capture());
-        ProximityActiveListener listener = captor.getValue();
+                ProximityCaptor.capture());
+        ProximityActiveListener proximityListener = ProximityCaptor.getValue();
+
+        ArgumentCaptor<DisplayListener> DisplayCaptor =
+                ArgumentCaptor.forClass(DisplayListener.class);
+        verify(mInjector).registerDisplayListener(DisplayCaptor.capture(), any(Handler.class),
+                eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                        | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                        | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+        DisplayListener displayListener = DisplayCaptor.getValue();
 
         // Verify that there is no proximity vote initially
         Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
@@ -1353,13 +1361,38 @@
         when(mDisplayManagerInternalMock.getRefreshRateForDisplayAndSensor(eq(DISPLAY_ID), eq(null),
                   eq(Sensor.STRING_TYPE_PROXIMITY))).thenReturn(new RefreshRateRange(60, 60));
 
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+
         // Set the proximity to active and verify that we added a vote.
-        listener.onProximityActive(true);
+        proximityListener.onProximityActive(true);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertVoteForRefreshRate(vote, 60.f);
+
+        // Set the display state to doze and verify that the vote is gone
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+        displayListener.onDisplayAdded(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertNull(vote);
+
+        // Set the display state to on and verify that we added the vote back.
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+        displayListener.onDisplayChanged(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertVoteForRefreshRate(vote, 60.f);
+
+        // Set the display state to doze and verify that the vote is gone
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+        displayListener.onDisplayAdded(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertNull(vote);
+
+        // Remove the display to cause the doze state to be removed
+        displayListener.onDisplayRemoved(DISPLAY_ID);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
         assertVoteForRefreshRate(vote, 60.f);
 
         // Turn prox off and verify vote is gone.
-        listener.onProximityActive(false);
+        proximityListener.onProximityActive(false);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
         assertNull(vote);
     }
@@ -1710,6 +1743,11 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            return false;
+        }
+
         void notifyPeakRefreshRateChanged() {
             if (mPeakRefreshRateObserver != null) {
                 mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index a0fcd83..35c7e5d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -29,7 +29,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
@@ -539,69 +538,4 @@
 
         verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
     }
-
-    @Test
-    public void handleReportAudioStatus_SamOnArcOn_setStreamVolumeCalled() {
-        mNativeWrapper.setPortConnectionStatus(2, true);
-        HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
-                ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
-        mNativeWrapper.onCecMessage(hdmiCecMessage);
-
-        HdmiCecFeatureAction systemAudioAutoInitiationAction =
-                new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
-        mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
-
-        HdmiCecMessage reportSystemAudioMode =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(
-                        ADDR_AUDIO_SYSTEM,
-                        mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
-                        true);
-        mHdmiControlService.handleCecCommand(reportSystemAudioMode);
-
-        HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
-                ADDR_AUDIO_SYSTEM,
-                ADDR_TV);
-        mNativeWrapper.onCecMessage(requestArcInitiation);
-
-        mTestLooper.dispatchAll();
-
-        // SAM and ARC must be on
-        assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
-        assertTrue(mHdmiCecLocalDeviceTv.isArcEstablished());
-
-        HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
-                ADDR_AUDIO_SYSTEM,
-                ADDR_TV,
-                50, // Volume of incoming message does not affect HDMI-CEC logic
-                false);
-        mNativeWrapper.onCecMessage(reportAudioStatus);
-
-        mTestLooper.dispatchAll();
-
-        verify(mAudioManager, times(1)).setStreamVolume(anyInt(), anyInt(), anyInt());
-    }
-
-    @Test
-    public void handleReportAudioStatus_SamOff_setStreamVolumeNotCalled() {
-        // Emulate Audio device on port 0x1000 (does not support ARC)
-        mNativeWrapper.setPortConnectionStatus(1, true);
-        HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
-                ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
-        mNativeWrapper.onCecMessage(hdmiCecMessage);
-
-        mTestLooper.dispatchAll();
-
-        assertFalse(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
-
-        HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
-                ADDR_AUDIO_SYSTEM,
-                ADDR_TV,
-                50, // Volume of incoming message does not affect HDMI-CEC logic
-                false);
-        mNativeWrapper.onCecMessage(reportAudioStatus);
-
-        mTestLooper.dispatchAll();
-
-        verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 2704308..6492e0f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -33,6 +33,8 @@
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -59,6 +61,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
@@ -322,6 +325,18 @@
     }
 
     @Test
+    public void normalBoot_queuedActionsStartedAfterBoot() {
+        Mockito.clearInvocations(mAudioSystemDeviceSpy);
+        Mockito.clearInvocations(mPlaybackDeviceSpy);
+
+        mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED);
+        mTestLooper.dispatchAll();
+
+        verify(mAudioSystemDeviceSpy, times(1)).startQueuedActions();
+        verify(mPlaybackDeviceSpy, times(1)).startQueuedActions();
+    }
+
+    @Test
     public void initialPowerStatus_normalBoot_goToStandby_broadcastsPowerStatus_2_0() {
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
new file mode 100644
index 0000000..00e3bf1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.RequestSadAction.RequestSadCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class RequestSadActionTest {
+
+    private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
+    private static final ArrayList<Integer> CODECS_TO_QUERY_1 = new ArrayList<Integer>(
+            Arrays.asList(Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
+                    Constants.AUDIO_CODEC_MPEG1, Constants.AUDIO_CODEC_MP3));
+    private static final ArrayList<Integer> CODECS_TO_QUERY_2 = new ArrayList<Integer>(
+            Arrays.asList(Constants.AUDIO_CODEC_MPEG2, Constants.AUDIO_CODEC_AAC,
+                    Constants.AUDIO_CODEC_DTS, Constants.AUDIO_CODEC_ATRAC));
+    private static final ArrayList<Integer> CODECS_TO_QUERY_3 = new ArrayList<Integer>(
+            Arrays.asList(Constants.AUDIO_CODEC_ONEBITAUDIO, Constants.AUDIO_CODEC_DDP,
+                    Constants.AUDIO_CODEC_DTSHD, Constants.AUDIO_CODEC_TRUEHD));
+    private static final ArrayList<Integer> CODECS_TO_QUERY_4 = new ArrayList<Integer>(
+            Arrays.asList(Constants.AUDIO_CODEC_DST, Constants.AUDIO_CODEC_WMAPRO,
+                    Constants.AUDIO_CODEC_MAX));
+
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
+    private FakeNativeWrapper mNativeWrapper;
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+    private List<byte[]> mSupportedSads;
+    private RequestSadCallback mCallback =
+            new RequestSadCallback() {
+                @Override
+                public void onRequestSadDone(
+                        List<byte[]> supportedSads) {
+                    mSupportedSads = supportedSads;
+                }
+            };
+    @Mock
+    private IPowerManager mIPowerManagerMock;
+    @Mock
+    private IThermalService mIThermalServiceMock;
+
+    private static byte[] concatenateSads(List<byte[]> sads) {
+        byte[] concatenatedSads = new byte[sads.size() * 3];
+        for (int i = 0; i < sads.size(); i++) {
+            for (int j = 0; j < 3; j++) {
+                concatenatedSads[3 * i + j] = sads.get(i)[j];
+            }
+        }
+        return concatenatedSads;
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = InstrumentationRegistry.getTargetContext();
+        mMyLooper = mTestLooper.getLooper();
+
+        mHdmiControlService =
+                new HdmiControlService(InstrumentationRegistry.getTargetContext(),
+                        Collections.emptyList()) {
+                    @Override
+                    boolean isControlEnabled() {
+                        return true;
+                    }
+
+                    @Override
+                    void wakeUp() {
+                    }
+
+                    @Override
+                    protected void writeStringSystemProperty(String key, String value) {
+                        // do nothing
+                    }
+
+                    @Override
+                    boolean isPowerStandbyOrTransient() {
+                        return false;
+                    }
+
+                    @Override
+                    protected PowerManager getPowerManager() {
+                        return new PowerManager(context, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mMyLooper));
+                    }
+                };
+
+        mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
+        mHdmiCecLocalDeviceTv.init();
+        mHdmiControlService.setIoLooper(mMyLooper);
+        mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+                mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mLocalDevices.add(mHdmiCecLocalDeviceTv);
+        mHdmiControlService.initService();
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mNativeWrapper.setPhysicalAddress(0x0000);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+    }
+
+    @Test
+    public void noResponse_queryAgain_emptyResult() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void featureAbort_dontQueryAgain_emptyResult() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+        HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
+                Constants.ABORT_INVALID_OPERAND);
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(featureAbort);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(featureAbort);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(featureAbort);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        action.processCommand(featureAbort);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void allSupported_completeResult() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_1 = new byte[]{
+                0x01, 0x18, 0x4A,
+                0x02, 0x64, 0x5A,
+                0x03, 0x4B, 0x00,
+                0x04, 0x20, 0x0A};
+        HdmiCecMessage response1 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_1);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response1);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_2 = new byte[]{
+                0x05, 0x18, 0x4A,
+                0x06, 0x64, 0x5A,
+                0x07, 0x4B, 0x00,
+                0x08, 0x20, 0x0A};
+        HdmiCecMessage response2 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_2);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response2);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_3 = new byte[]{
+                0x09, 0x18, 0x4A,
+                0x0A, 0x64, 0x5A,
+                0x0B, 0x4B, 0x00,
+                0x0C, 0x20, 0x0A};
+        HdmiCecMessage response3 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_3);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response3);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_4 = new byte[]{
+                0x0D, 0x18, 0x4A,
+                0x0E, 0x64, 0x5A,
+                0x0F, 0x4B, 0x00};
+        HdmiCecMessage response4 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_4);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        action.processCommand(response4);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(15);
+        assertThat(Arrays.equals(sadsToRespond_1,
+                concatenateSads(mSupportedSads.subList(0, 4)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_2,
+                concatenateSads(mSupportedSads.subList(4, 8)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_3,
+                concatenateSads(mSupportedSads.subList(8, 12)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_4,
+                concatenateSads(mSupportedSads.subList(12, 15)))).isTrue();
+    }
+
+    @Test
+    public void subsetSupported_subsetResult() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_1 = new byte[]{
+                0x01, 0x18, 0x4A,
+                0x03, 0x4B, 0x00,
+                0x04, 0x20, 0x0A};
+        HdmiCecMessage response1 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_1);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response1);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_2 = new byte[]{
+                0x08, 0x20, 0x0A};
+        HdmiCecMessage response2 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_2);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response2);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_3 = new byte[]{
+                0x09, 0x18, 0x4A,
+                0x0A, 0x64, 0x5A,
+                0x0B, 0x4B, 0x00,
+                0x0C, 0x20, 0x0A};
+        HdmiCecMessage response3 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_3);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response3);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_4 = new byte[]{
+                0x0F, 0x4B, 0x00};
+        HdmiCecMessage response4 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_4);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        action.processCommand(response4);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(9);
+        assertThat(Arrays.equals(sadsToRespond_1,
+                concatenateSads(mSupportedSads.subList(0, 3)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_2,
+                concatenateSads(mSupportedSads.subList(3, 4)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_3,
+                concatenateSads(mSupportedSads.subList(4, 8)))).isTrue();
+        assertThat(Arrays.equals(sadsToRespond_4,
+                concatenateSads(mSupportedSads.subList(8, 9)))).isTrue();
+    }
+
+    @Test
+    public void invalidCodecs_emptyResults() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_1 = new byte[]{
+                0x20, 0x18, 0x4A,
+                0x21, 0x64, 0x5A,
+                0x22, 0x4B, 0x00,
+                0x23, 0x20, 0x0A};
+        HdmiCecMessage response1 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_1);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response1);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_2 = new byte[]{
+                0x24, 0x18, 0x4A,
+                0x25, 0x64, 0x5A,
+                0x26, 0x4B, 0x00,
+                0x27, 0x20, 0x0A};
+        HdmiCecMessage response2 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_2);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response2);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_3 = new byte[]{
+                0x28, 0x18, 0x4A,
+                0x29, 0x64, 0x5A,
+                0x2A, 0x4B, 0x00,
+                0x2B, 0x20, 0x0A};
+        HdmiCecMessage response3 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_3);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response3);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_4 = new byte[]{
+                0x2C, 0x18, 0x4A,
+                0x2D, 0x64, 0x5A,
+                0x2E, 0x4B, 0x00};
+        HdmiCecMessage response4 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_4);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        action.processCommand(response4);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void invalidMessageLength_queryAgain() {
+        RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
+                mCallback);
+        action.start();
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_1 = new byte[]{
+                0x01, 0x18,
+                0x02, 0x64, 0x5A,
+                0x03, 0x4B, 0x00,
+                0x04, 0x20, 0x0A};
+        HdmiCecMessage response1 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_1);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response1);
+        mTestLooper.dispatchAll();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected2 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_2.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_2 = new byte[]{
+                0x05, 0x18, 0x4A,
+                0x06, 0x64, 0x5A,
+                0x07,
+                0x08, 0x20, 0x0A};
+        HdmiCecMessage response2 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_2);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response2);
+        mTestLooper.dispatchAll();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected2);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected3 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_3.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_3 = new byte[0];
+        HdmiCecMessage response3 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_3);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response3);
+        mTestLooper.dispatchAll();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected3);
+        mNativeWrapper.clearResultMessages();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage expected4 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
+                Constants.ADDR_AUDIO_SYSTEM,
+                CODECS_TO_QUERY_4.stream().mapToInt(i -> i).toArray());
+        byte[] sadsToRespond_4 = new byte[]{
+                0x0D, 0x18, 0x4A,
+                0x0E, 0x64, 0x5A,
+                0x0F, 0x4B};
+        HdmiCecMessage response4 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
+                Constants.ADDR_AUDIO_SYSTEM,
+                mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(), sadsToRespond_4);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        mNativeWrapper.clearResultMessages();
+        action.processCommand(response4);
+        mTestLooper.dispatchAll();
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getResultMessages()).contains(expected4);
+        mTestLooper.moveTimeForward(TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        assertThat(mSupportedSads.size()).isEqualTo(0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 8b8a7e6..2bda120 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -40,6 +40,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -232,6 +233,21 @@
     }
 
     @Test
+    public void testGetStagedApexInfos_throwRunTimeException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).getStagedApexInfos(any());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.getStagedApexInfos(testParamsWithChildren()));
+    }
+
+    @Test
+    public void testGetStagedApexInfos_returnsEmptyArrayOnError() throws RemoteException {
+        doThrow(ServiceSpecificException.class).when(mApexService).getStagedApexInfos(any());
+
+        assertThat(mApexManager.getStagedApexInfos(testParamsWithChildren())).hasLength(0);
+    }
+
+    @Test
     public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
         doAnswer(invocation -> {
             throw new Exception();
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 1b6bddc..15f57e3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -17,7 +17,8 @@
 package com.android.server.pm;
 
 
-import android.content.pm.PackageParser;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
+
 import android.content.pm.Signature;
 import android.test.AndroidTestCase;
 import android.util.ArrayMap;
@@ -60,11 +61,11 @@
         assertEquals(0, aliases.size());
     }
 
-    /* test equivalence of PackageManager cert encoding and PackageParser manifest keys */
+    /* test equivalence of PackageManager cert encoding and ParsingPackageUtils manifest keys */
     public void testPublicKeyCertReprEquiv() throws CertificateException {
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
 
         Signature sigA = new Signature(KeySetStrings.ctsKeySetCertA);
         Signature sigB = new Signature(KeySetStrings.ctsKeySetCertB);
@@ -99,9 +100,9 @@
                 new WatchedArrayMap<String, PackageSetting>();
         KeySetManagerService ksms = new KeySetManagerService(packagesMap);
 
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
 
         assertEquals(ksms.encodePublicKey(keyA), KeySetStrings.ctsKeySetPublicKeyA);
         assertEquals(ksms.encodePublicKey(keyB), KeySetStrings.ctsKeySetPublicKeyB);
@@ -119,7 +120,7 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
@@ -146,7 +147,7 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
@@ -176,12 +177,12 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* now upgrade with new key */
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.removeAt(0);
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
@@ -213,13 +214,13 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
         mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
         /* now upgrade with new key */
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.removeAt(0);
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
@@ -256,13 +257,13 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys1 = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys1.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys1);
 
         /* collect second signing key and add */
         ArraySet<PublicKey> signingKeys2 = new ArraySet<PublicKey>();
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys2.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys2);
 
@@ -301,7 +302,7 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
 
@@ -334,12 +335,12 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
 
         /* give ps2 a superset (add keyB) */
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
 
@@ -375,12 +376,12 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
         /* now with additional key */
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         signingKeys.add(keyB);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
@@ -413,7 +414,7 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -440,7 +441,7 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         definedKS.put("aliasA2", keys);
@@ -470,14 +471,14 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different defined key-set */
         keys = new ArraySet<PublicKey>();
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys);
@@ -510,14 +511,14 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different set w/same alias as before */
         keys = new ArraySet<PublicKey>();
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys.add(keyB);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -548,8 +549,8 @@
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
         ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys1.add(keyA);
         keys2.add(keyB);
         definedKS.put("aliasA", keys1);
@@ -558,7 +559,7 @@
 
         /* now upgrade to different set (B, C) */
         keys1 = new ArraySet<PublicKey>();
-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+        PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
         keys1.add(keyC);
         definedKS.remove("aliasA");
         definedKS.put("aliasC", keys1);
@@ -612,14 +613,14 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys1 = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys1.add(keyA);
         definedKS.put("aliasA", keys1);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
 
         /* now upgrade to different set */
         ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>();
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys2.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys2);
@@ -655,7 +656,7 @@
         /* collect key and add, and denote as an upgrade keyset */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -677,7 +678,7 @@
         /* collect key and add and try to specify bogus upgrade keyset */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -704,7 +705,7 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
         definedKS.put("aliasA", keys);
         mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS);
@@ -713,7 +714,7 @@
         mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS);
 
         keys = new ArraySet<PublicKey>();
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
         keys.add(keyB);
         definedKS.remove("aliasA");
         definedKS.put("aliasB", keys);
@@ -730,7 +731,7 @@
 
         /* collect signing key and add */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps, signingKeys);
 
@@ -755,7 +756,7 @@
 
         /* collect signing key and add for both packages */
         ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         signingKeys.add(keyA);
         mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys);
         mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys);
@@ -781,7 +782,7 @@
         /* collect key and add */
         ArrayMap<String, ArraySet<PublicKey>> definedKS = new ArrayMap<String, ArraySet<PublicKey>>();
         ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
         keys.add(keyA);
 
         /* removal requires signing keyset to be specified (since all apps are
diff --git a/services/tests/servicestests/src/com/android/server/pm/OWNERS b/services/tests/servicestests/src/com/android/server/pm/OWNERS
index e15b5f5..2f51994 100644
--- a/services/tests/servicestests/src/com/android/server/pm/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/pm/OWNERS
@@ -1,3 +1,7 @@
 include /services/core/java/com/android/server/pm/OWNERS
 
 per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+
+# apex support
+per-file ApexManagerTest.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 976a588..f241fe1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -101,16 +101,15 @@
 
         PackageSenderImpl sender = new PackageSenderImpl();
         PackageSetting setting = null;
-        PackageManagerService.PackageRemovedInfo pri =
-                new PackageManagerService.PackageRemovedInfo(sender);
+        PackageRemovedInfo pri = new PackageRemovedInfo(sender);
 
         // Initial conditions: nothing there
-        Assert.assertNull(pri.removedUsers);
-        Assert.assertNull(pri.broadcastUsers);
+        Assert.assertNull(pri.mRemovedUsers);
+        Assert.assertNull(pri.mBroadcastUsers);
 
         // populateUsers with nothing leaves nothing
         pri.populateUsers(null, setting);
-        Assert.assertNull(pri.broadcastUsers);
+        Assert.assertNull(pri.mBroadcastUsers);
 
         // Create a real (non-null) PackageSetting and confirm that the removed
         // users are copied properly
@@ -126,22 +125,22 @@
         pri.populateUsers(new int[] {
                 1, 2, 3, 4, 5
         }, setting);
-        Assert.assertNotNull(pri.broadcastUsers);
-        Assert.assertEquals(5, pri.broadcastUsers.length);
-        Assert.assertNotNull(pri.instantUserIds);
-        Assert.assertEquals(0, pri.instantUserIds.length);
+        Assert.assertNotNull(pri.mBroadcastUsers);
+        Assert.assertEquals(5, pri.mBroadcastUsers.length);
+        Assert.assertNotNull(pri.mInstantUserIds);
+        Assert.assertEquals(0, pri.mInstantUserIds.length);
 
         // Exclude a user
-        pri.broadcastUsers = null;
+        pri.mBroadcastUsers = null;
         final int EXCLUDED_USER_ID = 4;
         setting.setInstantApp(true, EXCLUDED_USER_ID);
         pri.populateUsers(new int[] {
                 1, 2, 3, EXCLUDED_USER_ID, 5
         }, setting);
-        Assert.assertNotNull(pri.broadcastUsers);
-        Assert.assertEquals(4, pri.broadcastUsers.length);
-        Assert.assertNotNull(pri.instantUserIds);
-        Assert.assertEquals(1, pri.instantUserIds.length);
+        Assert.assertNotNull(pri.mBroadcastUsers);
+        Assert.assertEquals(4, pri.mBroadcastUsers.length);
+        Assert.assertNotNull(pri.mInstantUserIds);
+        Assert.assertEquals(1, pri.mInstantUserIds.length);
 
         // TODO: test that sendApplicationHiddenForUser() actually fills in
         // broadcastUsers
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 22fb76b..45e2ab4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -22,6 +22,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS;
 import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
+import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
 import static android.content.res.Resources.ID_NULL;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -39,7 +40,6 @@
 import android.app.PropertyInvalidatedCache;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
@@ -1216,9 +1216,9 @@
         assertThat(KeySetUtils.getPubKeyRefCount(ksms, 3), is(1));
 
         /* verify public keys properly read */
-        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
-        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
-        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
+        PublicKey keyA = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
+        PublicKey keyB = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
+        PublicKey keyC = parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
         assertThat(KeySetUtils.getPubKey(ksms, 1), is(keyA));
         assertThat(KeySetUtils.getPubKey(ksms, 2), is(keyB));
         assertThat(KeySetUtils.getPubKey(ksms, 3), is(keyC));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e8c5fb3..38b98ca 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -949,7 +949,7 @@
                 .addConfigPreference(new ConfigurationInfo())
                 .addReqFeature(new FeatureInfo())
                 .addFeatureGroup(new FeatureGroupInfo())
-                .setCompileSdkVersionCodename("foo23")
+                .setCompileSdkVersionCodeName("foo23")
                 .setCompileSdkVersion(100)
                 .setOverlayCategory("foo24")
                 .setOverlayIsStatic(true)
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 12fb400..54bfe01 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -108,8 +108,8 @@
         return this;
     }
 
-    PackageManagerService.ScanRequest build() {
-        return new PackageManagerService.ScanRequest(
+    ScanRequest build() {
+        return new ScanRequest(
                 mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
                 mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
                 mUser, mCpuAbiOverride);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 8153242..6c6cfd4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -129,16 +129,16 @@
 
     @Test
     public void newInstallSimpleAllNominal() throws Exception {
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .build();
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
-        assertThat(scanResult.existingSettingCopied, is(false));
+        assertThat(scanResult.mExistingSettingCopied, is(false));
         assertPathsNotDerived(scanResult);
     }
 
@@ -147,38 +147,38 @@
         final int[] userIds = {0, 10, 11};
         when(mMockUserManager.getUserIds()).thenReturn(userIds);
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName(null)
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .build();
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
         for (int uid : userIds) {
-            assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+            assertThat(scanResult.mPkgSetting.readUserState(uid).installed, is(true));
         }
     }
 
     @Test
     public void installRealPackageName() throws Exception {
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName("com.package.real")
                         .build();
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+        assertThat(scanResult.mPkgSetting.realName, is("com.package.real"));
 
-        final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+        final ScanRequest scanRequestNoRealPkg =
                 createBasicScanRequestBuilder(
                         createBasicPackage(DUMMY_PACKAGE_NAME)
                                 .setRealPackage("com.package.real"))
                         .build();
 
-        final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
-        assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+        final ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+        assertThat(scanResultNoReal.mPkgSetting.realName, nullValue());
     }
 
     @Test
@@ -189,25 +189,25 @@
                 .setPrimaryCpuAbiString("primaryCpuAbi")
                 .setSecondaryCpuAbiString("secondaryCpuAbi")
                 .build();
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .setPkgSetting(pkgSetting)
                         .build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.existingSettingCopied, is(true));
+        assertThat(scanResult.mExistingSettingCopied, is(true));
 
         // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
-        assertNotSame(pkgSetting, scanResult.pkgSetting);
+        assertNotSame(pkgSetting, scanResult.mPkgSetting);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
 
-        assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
-        assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
-        assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+        assertThat(scanResult.mPkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+        assertThat(scanResult.mPkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+        assertThat(scanResult.mPkgSetting.cpuAbiOverrideString, nullValue());
 
         assertPathsNotDerived(scanResult);
     }
@@ -221,13 +221,13 @@
                         .setInstantAppUserState(0, true)
                         .build();
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
     }
@@ -244,24 +244,24 @@
                 .setBaseApkPath("/some/path.apk")
                 .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
-        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
+        final ScanRequest scanRequest = new ScanRequestBuilder(pkg)
                 .setUser(UserHandle.of(0)).build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
-        assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
-        assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
-        assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
-        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+        assertThat(scanResult.mStaticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+        assertThat(scanResult.mStaticSharedLibraryInfo.getName(), is("static.lib"));
+        assertThat(scanResult.mStaticSharedLibraryInfo.getLongVersion(), is(123L));
+        assertThat(scanResult.mStaticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+        assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
                 is("static.lib.pkg"));
-        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+        assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
                 is(pkg.getLongVersionCode()));
-        assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+        assertThat(scanResult.mStaticSharedLibraryInfo.getAllCodePaths(),
                 hasItems("/some/path.apk", "/some/other/path.apk"));
-        assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
-        assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+        assertThat(scanResult.mStaticSharedLibraryInfo.getDependencies(), nullValue());
+        assertThat(scanResult.mStaticSharedLibraryInfo.getDependentPackages(), empty());
     }
 
     @Test
@@ -276,13 +276,13 @@
                 .setBaseApkPath("/some/path.apk")
                 .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+        final SharedLibraryInfo dynamicLib0 = scanResult.mDynamicSharedLibraryInfos.get(0);
         assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
         assertThat(dynamicLib0.getName(), is("liba"));
         assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -295,7 +295,7 @@
         assertThat(dynamicLib0.getDependencies(), nullValue());
         assertThat(dynamicLib0.getDependentPackages(), empty());
 
-        final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+        final SharedLibraryInfo dynamicLib1 = scanResult.mDynamicSharedLibraryInfos.get(1);
         assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
         assertThat(dynamicLib1.getName(), is("libb"));
         assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -321,10 +321,10 @@
                 .hideAsParsed());
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(
+        final ScanResult scanResult = executeScan(
                 new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
 
-        assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
+        assertThat(scanResult.mPkgSetting.volumeUuid, is(UUID_TWO.toString()));
     }
 
     @Test
@@ -337,7 +337,7 @@
                         .hideAsParsed());
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
+        final ScanResult scanResult = executeScan(new ScanRequestBuilder(
                 basicPackage)
                 .setPkgSetting(pkgSetting)
                 .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -356,12 +356,12 @@
                         .hideAsParsed();
 
 
-        final PackageManagerService.ScanResult result =
+        final ScanResult result =
                 executeScan(new ScanRequestBuilder(basicPackage)
                         .setOriginalPkgSetting(originalPkgSetting)
                         .build());
 
-        assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
+        assertThat(result.mRequest.mParsedPackage.getPackageName(), is("original.package"));
     }
 
     @Test
@@ -373,14 +373,14 @@
                         .setInstantAppUserState(0, true)
                         .build();
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_FULL_APP)
                         .build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
     }
@@ -394,14 +394,14 @@
                         .setInstantAppUserState(0, false)
                         .build();
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_INSTANT_APP)
                         .build();
 
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
         assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
     }
@@ -413,17 +413,17 @@
                         .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
                         .build();
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .setDisabledPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_NEW_INSTALL)
                         .build();
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
-                scanResult.pkgSetting);
+        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
+                scanResult.mPkgSetting);
         assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
     }
 
@@ -432,14 +432,14 @@
         final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
                 .addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
 
-        final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+        final ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
                 mMockInjector,
                 true /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
 
-        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
-                scanResult.request.pkgSetting);
+        int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
+                scanResult.mRequest.mPkgSetting);
         assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
     }
 
@@ -449,13 +449,13 @@
                 .hideAsParsed())
                 .setSystem(true);
 
-        final PackageManagerService.ScanRequest scanRequest =
+        final ScanRequest scanRequest =
                 createBasicScanRequestBuilder(pkg)
                         .build();
 
-        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+        final ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.pkgSetting.installSource.isOrphaned, is(true));
+        assertThat(scanResult.mPkgSetting.installSource.isOrphaned, is(true));
     }
 
     private static Matcher<Integer> hasFlag(final int flag) {
@@ -478,9 +478,9 @@
         };
     }
 
-    private PackageManagerService.ScanResult executeScan(
-            PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
-        PackageManagerService.ScanResult result = PackageManagerService.scanPackageOnlyLI(
+    private ScanResult executeScan(
+            ScanRequest scanRequest) throws PackageManagerException {
+        ScanResult result = PackageManagerService.scanPackageOnlyLI(
                 scanRequest,
                 mMockInjector,
                 false /*isUnderFactoryTest*/,
@@ -488,7 +488,7 @@
 
         // Need to call hideAsFinal to cache derived fields. This is normally done in PMS, but not
         // in this cut down flow used for the test.
-        ((ParsedPackage) result.pkgSetting.pkg).hideAsFinal();
+        ((ParsedPackage) result.mPkgSetting.pkg).hideAsFinal();
         return result;
     }
 
@@ -529,10 +529,10 @@
     }
 
     private static void assertBasicPackageScanResult(
-            PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
-        assertThat(scanResult.success, is(true));
+            ScanResult scanResult, String packageName, boolean isInstant) {
+        assertThat(scanResult.mSuccess, is(true));
 
-        final PackageSetting pkgSetting = scanResult.pkgSetting;
+        final PackageSetting pkgSetting = scanResult.mPkgSetting;
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
 
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
@@ -540,35 +540,35 @@
         assertBasicApplicationInfo(scanResult, applicationInfo);
     }
 
-    private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+    private static void assertBasicPackageSetting(ScanResult scanResult,
             String packageName, boolean isInstant, PackageSetting pkgSetting) {
         assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
         assertThat(pkgSetting.getInstantApp(0), is(isInstant));
         assertThat(pkgSetting.usesStaticLibraries,
                 arrayContaining("some.static.library", "some.other.static.library"));
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
-        assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
+        assertThat(pkgSetting.pkg, is(scanResult.mRequest.mParsedPackage));
         assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
     }
 
-    private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+    private static void assertBasicApplicationInfo(ScanResult scanResult,
             ApplicationInfo applicationInfo) {
         assertThat(applicationInfo.processName,
-                is(scanResult.request.parsedPackage.getPackageName()));
+                is(scanResult.mRequest.mParsedPackage.getPackageName()));
 
         final int uid = applicationInfo.uid;
         assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
 
         final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
                 applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
-                scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
+                scanResult.mRequest.mParsedPackage.getPackageName()).getAbsolutePath();
         assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
         assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
     }
 
-    private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
-        PackageSetting pkgSetting = scanResult.pkgSetting;
+    private static void assertAbiAndPathssDerived(ScanResult scanResult) {
+        PackageSetting pkgSetting = scanResult.mPkgSetting;
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
                 pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
         assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
@@ -581,8 +581,8 @@
         assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
     }
 
-    private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
-        PackageSetting pkgSetting = scanResult.pkgSetting;
+    private static void assertPathsNotDerived(ScanResult scanResult) {
+        PackageSetting pkgSetting = scanResult.mPkgSetting;
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
                 pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
         assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 581ff54..b7eddb3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -29,6 +29,7 @@
 import android.content.pm.PermissionInfo
 import android.content.pm.ProviderInfo
 import android.content.pm.ServiceInfo
+import android.content.pm.parsing.ParsingPackageUtils
 import android.os.Bundle
 import android.os.Debug
 import android.os.Environment
@@ -109,7 +110,7 @@
             apks.mapNotNull {
                 try {
                     packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) to
-                            packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR,
+                            packageParser2.parsePackage(it, ParsingPackageUtils.PARSE_IS_SYSTEM_DIR,
                                     false)
                 } catch (ignored: Exception) {
                     // It is intentional that a failure of either call here will result in failing
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index 5012ca9..6e3f754 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -210,7 +210,7 @@
         @Override
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                FaceDownDetector faceDownDetector) {
+                FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
             return mNotifierMock;
         }
 
@@ -298,6 +298,7 @@
                         BatteryStats.SERVICE_NAME)),
                 mInjector.createSuspendBlocker(mService, "testBlocker"),
                 null,
+                null,
                 null);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index b431614..e84e365 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -215,7 +215,7 @@
             @Override
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                     SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
-                    FaceDownDetector faceDownDetector) {
+                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) {
                 return mNotifierMock;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
index 65a9759..4a25323 100644
--- a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
+++ b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
@@ -19,19 +19,31 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
+import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
+
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 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.time.Clock;
+import java.time.ZoneOffset;
+
 /** Test that the ledger records transactions correctly. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class LedgerTest {
 
+    @Before
+    public void setUp() {
+        TareUtils.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+    }
+
     @Test
     public void testInitialState() {
         final Ledger ledger = new Ledger();
@@ -72,4 +84,45 @@
         assertEquals(1, ledger.get24HourSum(1, 27 * HOUR_IN_MILLIS));
         assertEquals(0, ledger.get24HourSum(1, 28 * HOUR_IN_MILLIS));
     }
+
+    @Test
+    public void testRemoveOldTransactions() {
+        final Ledger ledger = new Ledger();
+        ledger.removeOldTransactions(24 * HOUR_IN_MILLIS);
+        assertNull(ledger.getEarliestTransaction());
+
+        final long now = getCurrentTimeMillis();
+        Ledger.Transaction transaction1 = new Ledger.Transaction(
+                now - 48 * HOUR_IN_MILLIS, now - 40 * HOUR_IN_MILLIS, 1, null, 4800);
+        Ledger.Transaction transaction2 = new Ledger.Transaction(
+                now - 24 * HOUR_IN_MILLIS, now - 23 * HOUR_IN_MILLIS, 1, null, 600);
+        Ledger.Transaction transaction3 = new Ledger.Transaction(
+                now - 22 * HOUR_IN_MILLIS, now - 21 * HOUR_IN_MILLIS, 1, null, 600);
+        // Instant event
+        Ledger.Transaction transaction4 = new Ledger.Transaction(
+                now - 20 * HOUR_IN_MILLIS, now - 20 * HOUR_IN_MILLIS, 1, null, 500);
+        // Recent event
+        Ledger.Transaction transaction5 = new Ledger.Transaction(
+                now - 5 * MINUTE_IN_MILLIS, now - MINUTE_IN_MILLIS, 1, null, 400);
+        ledger.recordTransaction(transaction1);
+        ledger.recordTransaction(transaction2);
+        ledger.recordTransaction(transaction3);
+        ledger.recordTransaction(transaction4);
+        ledger.recordTransaction(transaction5);
+
+        assertEquals(transaction1, ledger.getEarliestTransaction());
+        ledger.removeOldTransactions(24 * HOUR_IN_MILLIS);
+        assertEquals(transaction2, ledger.getEarliestTransaction());
+        ledger.removeOldTransactions(23 * HOUR_IN_MILLIS);
+        assertEquals(transaction3, ledger.getEarliestTransaction());
+        // Shouldn't delete transaction3 yet since there's still a piece of it within the min age
+        // window.
+        ledger.removeOldTransactions(21 * HOUR_IN_MILLIS + 30 * MINUTE_IN_MILLIS);
+        assertEquals(transaction3, ledger.getEarliestTransaction());
+        // Instant event should be removed as soon as we hit the exact threshold.
+        ledger.removeOldTransactions(20 * HOUR_IN_MILLIS);
+        assertEquals(transaction5, ledger.getEarliestTransaction());
+        ledger.removeOldTransactions(0);
+        assertNull(ledger.getEarliestTransaction());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
index 0363625..da746ca 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
@@ -1006,24 +1006,25 @@
 
     @Test
     public void stateRecording() {
+        // The test provider enables state recording by default.
         ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
                 mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
         TestEnvironment testEnvironment = new TestEnvironment(
                 mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
 
-        // Initialize and check initial state.
+        // Initialize and check initial states.
         controllerImpl.initialize(testEnvironment, mTestCallback);
 
         {
             LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
             assertNull(state.getLastSuggestion());
-            assertTrue(state.getPrimaryProviderStates().isEmpty());
-            assertTrue(state.getSecondaryProviderStates().isEmpty());
+            assertProviderStates(state.getPrimaryProviderStates(),
+                    PROVIDER_STATE_STOPPED, PROVIDER_STATE_STARTED_INITIALIZING);
+            assertProviderStates(state.getSecondaryProviderStates(), PROVIDER_STATE_STOPPED);
         }
+        controllerImpl.clearRecordedProviderStates();
 
-        // State recording and simulate some provider behavior that will show up in the state
-        // recording.
-        controllerImpl.setProviderStateRecordingEnabled(true);
+        // Simulate some provider behavior that will show up in the state recording.
 
         // Simulate an uncertain event from the primary. This will start the secondary.
         mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
@@ -1032,19 +1033,14 @@
         {
             LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
             assertNull(state.getLastSuggestion());
-            List<LocationTimeZoneProvider.ProviderState> primaryProviderStates =
-                    state.getPrimaryProviderStates();
-            assertEquals(1, primaryProviderStates.size());
-            assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN,
-                    primaryProviderStates.get(0).stateEnum);
-            List<LocationTimeZoneProvider.ProviderState> secondaryProviderStates =
-                    state.getSecondaryProviderStates();
-            assertEquals(1, secondaryProviderStates.size());
-            assertEquals(PROVIDER_STATE_STARTED_INITIALIZING,
-                    secondaryProviderStates.get(0).stateEnum);
+            assertProviderStates(
+                    state.getPrimaryProviderStates(), PROVIDER_STATE_STARTED_UNCERTAIN);
+            assertProviderStates(
+                    state.getSecondaryProviderStates(), PROVIDER_STATE_STARTED_INITIALIZING);
         }
+        controllerImpl.clearRecordedProviderStates();
 
-        // Simulate an uncertain event from the primary. This will start the secondary.
+        // Simulate a certain event from the secondary.
         mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
                 USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
 
@@ -1052,23 +1048,27 @@
             LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
             assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
                     state.getLastSuggestion().getZoneIds());
-            List<LocationTimeZoneProvider.ProviderState> primaryProviderStates =
-                    state.getPrimaryProviderStates();
-            assertEquals(1, primaryProviderStates.size());
-            assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN, primaryProviderStates.get(0).stateEnum);
-            List<LocationTimeZoneProvider.ProviderState> secondaryProviderStates =
-                    state.getSecondaryProviderStates();
-            assertEquals(2, secondaryProviderStates.size());
-            assertEquals(PROVIDER_STATE_STARTED_CERTAIN, secondaryProviderStates.get(1).stateEnum);
+            assertProviderStates(state.getPrimaryProviderStates());
+            assertProviderStates(
+                    state.getSecondaryProviderStates(), PROVIDER_STATE_STARTED_CERTAIN);
         }
 
-        controllerImpl.setProviderStateRecordingEnabled(false);
+        controllerImpl.clearRecordedProviderStates();
         {
             LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
             assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
                     state.getLastSuggestion().getZoneIds());
-            assertTrue(state.getPrimaryProviderStates().isEmpty());
-            assertTrue(state.getSecondaryProviderStates().isEmpty());
+            assertProviderStates(state.getPrimaryProviderStates());
+            assertProviderStates(state.getSecondaryProviderStates());
+        }
+    }
+
+    private static void assertProviderStates(
+            List<LocationTimeZoneProvider.ProviderState> providerStates,
+            int... expectedStates) {
+        assertEquals(expectedStates.length, providerStates.size());
+        for (int i = 0; i < expectedStates.length; i++) {
+            assertEquals(expectedStates[i], providerStates.get(i).stateEnum);
         }
     }
 
@@ -1228,7 +1228,7 @@
         TestLocationTimeZoneProvider(ProviderMetricsLogger providerMetricsLogger,
                 ThreadingDomain threadingDomain, String providerName) {
             super(providerMetricsLogger, threadingDomain, providerName,
-                    new FakeTimeZoneProviderEventPreProcessor());
+                    new FakeTimeZoneProviderEventPreProcessor(), true /* recordStateChanges */);
         }
 
         public void setFailDuringInitialization(boolean failInitialization) {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index 0edb559..03d56c7 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
@@ -15,9 +15,6 @@
  */
 package com.android.server.timezonedetector.location;
 
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY;
-import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
-
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
 import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
@@ -26,8 +23,6 @@
 import static com.android.server.timezonedetector.location.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -36,8 +31,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.RemoteCallback;
 import android.platform.test.annotations.Presubmit;
 import android.service.timezone.TimeZoneProviderSuggestion;
 import android.util.IndentingPrintWriter;
@@ -54,7 +47,6 @@
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Tests for {@link LocationTimeZoneProvider}.
@@ -169,27 +161,6 @@
     }
 
     @Test
-    public void defaultHandleTestCommandImpl() {
-        String providerName = "primary";
-        StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
-        TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
-                providerMetricsLogger,
-                mTestThreadingDomain,
-                providerName,
-                mTimeZoneProviderEventPreProcessor);
-
-        TestCommand testCommand = TestCommand.createForTests("test", new Bundle());
-        AtomicReference<Bundle> resultReference = new AtomicReference<>();
-        RemoteCallback callback = new RemoteCallback(resultReference::set);
-        provider.handleTestCommand(testCommand, callback);
-
-        Bundle result = resultReference.get();
-        assertNotNull(result);
-        assertFalse(result.getBoolean(TEST_COMMAND_RESULT_SUCCESS_KEY));
-        assertNotNull(result.getString(TEST_COMMAND_RESULT_ERROR_KEY));
-    }
-
-    @Test
     public void stateRecording() {
         String providerName = "primary";
         StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
@@ -198,7 +169,6 @@
                 mTestThreadingDomain,
                 providerName,
                 mTimeZoneProviderEventPreProcessor);
-        provider.setStateChangeRecordingEnabled(true);
 
         // initialize()
         provider.initialize(mProviderListener);
@@ -244,7 +214,6 @@
                 mTestThreadingDomain,
                 providerName,
                 mTimeZoneProviderEventPreProcessor);
-        provider.setStateChangeRecordingEnabled(true);
         provider.initialize(mProviderListener);
         mTimeZoneProviderEventPreProcessor.enterUncertainMode();
 
@@ -315,8 +284,9 @@
                 @NonNull ThreadingDomain threadingDomain,
                 @NonNull String providerName,
                 @NonNull TimeZoneProviderEventPreProcessor timeZoneProviderEventPreProcessor) {
-            super(providerMetricsLogger,
-                    threadingDomain, providerName, timeZoneProviderEventPreProcessor);
+            super(providerMetricsLogger, threadingDomain, providerName,
+                    timeZoneProviderEventPreProcessor,
+                    true /* recordStateChanges */);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 2f36c7f..b8cb149 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -25,7 +25,6 @@
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputService;
-import android.media.tv.tuner.TunerFrontendInfo;
 import android.media.tv.tuner.frontend.FrontendSettings;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
@@ -33,6 +32,7 @@
 import android.media.tv.tunerresourcemanager.TunerCiCamRequest;
 import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
 import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
+import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 61b5c2b..4cc4d55 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -83,7 +83,7 @@
 @Presubmit
 public class VibrationThreadTest {
 
-    private static final int TEST_TIMEOUT_MILLIS = 1_000;
+    private static final int TEST_TIMEOUT_MILLIS = 900;
     private static final int UID = Process.ROOT_UID;
     private static final int VIBRATOR_ID = 1;
     private static final String PACKAGE_NAME = "package";
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
index 4e981b2..ae46f52 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
@@ -60,6 +60,9 @@
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         Log.i(TAG, "onStartCommand");
+        if (intent == null) {
+            return START_STICKY;
+        }
         int command = intent.getIntExtra(EXTRA_COMMAND, COMMAND_INVALID);
         if (command != COMMAND_INVALID) {
             final String targetPkg = intent.getStringExtra(EXTRA_TARGET_PACKAGE);
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 4b3771b..f21991d 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -475,7 +475,7 @@
 
     @Test
     public void requestProjection_failsForBogusPackageName() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(TestInjector.CALLING_UID + 1);
 
         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
@@ -485,7 +485,7 @@
 
     @Test
     public void requestProjection_failsIfNameNotFound() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
                 .thenThrow(new PackageManager.NameNotFoundException());
 
         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
@@ -495,7 +495,8 @@
 
     @Test
     public void requestProjection_failsIfNoProjectionTypes() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
 
         assertThrows(IllegalArgumentException.class,
                 () -> mService.requestProjection(mBinder, PROJECTION_TYPE_NONE, PACKAGE_NAME));
@@ -507,7 +508,8 @@
 
     @Test
     public void requestProjection_failsIfMultipleProjectionTypes() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
 
         // Don't use PROJECTION_TYPE_ALL because that's actually == -1 and will fail the > 0 check.
         int multipleProjectionTypes = PROJECTION_TYPE_AUTOMOTIVE | 0x0002 | 0x0004;
@@ -522,7 +524,8 @@
 
     @Test
     public void requestProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
-        doThrow(new SecurityException()).when(mPackageManager).getPackageUid(PACKAGE_NAME, 0);
+        doThrow(new SecurityException())
+                .when(mPackageManager).getPackageUidAsUser(eq(PACKAGE_NAME), anyInt());
 
         assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
                 PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
@@ -531,12 +534,14 @@
 
     @Test
     public void requestProjection_automotive_failsIfAlreadySetByOtherPackage() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
 
         String otherPackage = "Raconteurs";
-        when(mPackageManager.getPackageUid(otherPackage, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(otherPackage), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, otherPackage));
         assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
                 contains(PACKAGE_NAME));
@@ -544,7 +549,8 @@
 
     @Test
     public void requestProjection_failsIfCannotLinkToDeath() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         doThrow(new RemoteException()).when(mBinder).linkToDeath(any(), anyInt());
 
         assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
@@ -553,7 +559,8 @@
 
     @Test
     public void requestProjection() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         // Should work for all powers of two.
         for (int i = 0; i < Integer.SIZE; ++i) {
             int projectionType = 1 << i;
@@ -568,11 +575,12 @@
 
     @Test
     public void releaseProjection_failsForBogusPackageName() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
 
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(TestInjector.CALLING_UID + 1);
 
         assertThrows(SecurityException.class, () -> mService.releaseProjection(
@@ -582,10 +590,11 @@
 
     @Test
     public void releaseProjection_failsIfNameNotFound() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
                 .thenThrow(new PackageManager.NameNotFoundException());
 
         assertThrows(SecurityException.class, () -> mService.releaseProjection(
@@ -595,7 +604,8 @@
 
     @Test
     public void releaseProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
         doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
@@ -613,7 +623,8 @@
 
     @Test
     public void releaseProjection() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         requestAllPossibleProjectionTypes();
         assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
 
@@ -632,7 +643,8 @@
 
     @Test
     public void binderDeath_releasesProjection() throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         requestAllPossibleProjectionTypes();
         assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
         ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor = ArgumentCaptor.forClass(
@@ -647,7 +659,8 @@
     @Test
     public void getActiveProjectionTypes() throws Exception {
         assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
         mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
@@ -657,7 +670,8 @@
     @Test
     public void getProjectingPackages() throws Exception {
         assertTrue(mService.getProjectingPackages(PROJECTION_TYPE_ALL).isEmpty());
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE).size());
         assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_ALL).size());
@@ -681,7 +695,8 @@
     @Test
     public void addOnProjectionStateChangedListener_callsListenerIfProjectionActive()
             throws Exception {
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
 
@@ -710,7 +725,8 @@
 
         mService.removeOnProjectionStateChangedListener(listener);
         // Now set automotive projection, should not call back.
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         verify(listener, never()).onProjectionStateChanged(anyInt(), any());
     }
@@ -726,7 +742,8 @@
         verifyNoMoreInteractions(listener);
 
         // Now set automotive projection, should call back.
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
                 eq(List.of(PACKAGE_NAME)));
@@ -752,8 +769,9 @@
         int fakeProjectionType = 0x0002;
         int otherFakeProjectionType = 0x0004;
         String otherPackageName = "Internet Arms";
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
-        when(mPackageManager.getPackageUid(otherPackageName, 0))
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(otherPackageName), anyInt()))
                 .thenReturn(TestInjector.CALLING_UID);
         IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
         when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
@@ -806,7 +824,8 @@
 
         // Now kill the binder for the listener. This should remove it from the list of listeners.
         listenerDeathRecipient.getValue().binderDied();
-        when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+                .thenReturn(TestInjector.CALLING_UID);
         mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
         verify(listener, never()).onProjectionStateChanged(anyInt(), any());
     }
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 f57c416..7bbf3e6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4793,6 +4793,52 @@
     }
 
     @Test
+    public void testSetNotificationsShownFromListener_protectsCrossUserInformation()
+            throws RemoteException {
+        Notification.Builder nb = new Notification.Builder(
+                mContext, mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
+                null, 0);
+        final NotificationRecord r =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        // no security exception!
+        mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
+
+        verify(mAppUsageStats, never()).reportInterruptiveNotification(
+                anyString(), anyString(), anyInt());
+    }
+
+    @Test
+    public void testCancelNotificationsFromListener_protectsCrossUserInformation()
+            throws RemoteException {
+        Notification.Builder nb = new Notification.Builder(
+                mContext, mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
+                "tag" + System.currentTimeMillis(),  UserHandle.PER_USER_RANGE, 0,
+                nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE),
+                null, 0);
+        final NotificationRecord r =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        // no security exception!
+        mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()});
+
+        waitForIdle();
+        assertEquals(1, mService.getNotificationRecordCount());
+    }
+
+    @Test
     public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
             throws RemoteException {
         final NotificationRecord r = generateNotificationRecord(
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 fa1f4ac..b282cd7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -27,6 +27,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.argThat;
@@ -70,6 +71,7 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
+    private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
     private ActivityMetricsLogger mActivityMetricsLogger;
     private ActivityMetricsLogger.LaunchingState mLaunchingState;
     private ActivityMetricsLaunchObserver mLaunchObserver;
@@ -137,7 +139,7 @@
         // messages that are waiting for the lock.
         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)));
+        return verify(mock, timeout(TIMEOUT_MS));
     }
 
     private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
@@ -258,15 +260,40 @@
 
     @Test
     public void testOnActivityLaunchWhileSleeping() {
-        notifyActivityLaunching(mTopActivity.intent);
-        notifyActivityLaunched(START_SUCCESS, mTopActivity);
-        doReturn(true).when(mTopActivity.mDisplayContent).isSleeping();
-        mTopActivity.setState(ActivityRecord.State.RESUMED, "test");
-        mTopActivity.setVisibility(false);
+        notifyActivityLaunching(mTrampolineActivity.intent);
+        notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
+        doReturn(true).when(mTrampolineActivity.mDisplayContent).isSleeping();
+        mTrampolineActivity.setState(ActivityRecord.State.RESUMED, "test");
+        mTrampolineActivity.setVisibility(false);
         waitHandlerIdle(mAtm.mH);
         // Not cancel immediately because in one of real cases, the keyguard may be going away or
         // occluded later, then the activity can be drawn.
-        verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTopActivity));
+        verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+
+        clearInvocations(mLaunchObserver);
+        mLaunchTopByTrampoline = true;
+        mTopActivity.mVisibleRequested = false;
+        notifyActivityLaunching(mTopActivity.intent);
+        // It should schedule a message with UNKNOWN_VISIBILITY_CHECK_DELAY_MS to check whether
+        // the launch event is still valid.
+        notifyActivityLaunched(START_SUCCESS, mTopActivity);
+
+        // The posted message will acquire wm lock, so the test needs to release the lock to verify.
+        final Throwable error = awaitInWmLock(() -> {
+            try {
+                // Though the aborting target should be eqProto(mTopActivity), use any() to avoid
+                // any changes in proto that may cause failure by different arguments.
+                verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(any());
+            } catch (Throwable e) {
+                // Catch any errors including assertion because this runs in another thread.
+                return e;
+            }
+            return null;
+        });
+        // The launch event must be cancelled because the activity keeps invisible.
+        if (error != null) {
+            throw new AssertionError(error);
+        }
     }
 
     @Test
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 488875b..9ca09d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
@@ -145,6 +146,8 @@
 import org.mockito.invocation.InvocationOnMock;
 
 import java.util.ArrayList;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 
 /**
@@ -1601,16 +1604,23 @@
     }
 
     @Test
-    public void testRemoveImmediately() throws RemoteException {
-        final ActivityRecord activity = createActivityWithTask();
-        final WindowProcessController wpc = activity.app;
-        activity.getTask().removeImmediately("test");
-
-        verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
-                isA(DestroyActivityItem.class));
-        assertNull(activity.app);
-        assertEquals(DESTROYED, activity.getState());
-        assertFalse(wpc.hasActivities());
+    public void testRemoveImmediately() {
+        final Consumer<Consumer<ActivityRecord>> test = setup -> {
+            final ActivityRecord activity = createActivityWithTask();
+            final WindowProcessController wpc = activity.app;
+            setup.accept(activity);
+            activity.getTask().removeImmediately("test");
+            try {
+                verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
+                        isA(DestroyActivityItem.class));
+            } catch (RemoteException ignored) {
+            }
+            assertNull(activity.app);
+            assertEquals(DESTROYED, activity.getState());
+            assertFalse(wpc.hasActivities());
+        };
+        test.accept(activity -> activity.setState(RESUMED, "test"));
+        test.accept(activity -> activity.finishing = true);
     }
 
     @Test
@@ -2506,7 +2516,7 @@
                 false, false);
         waitUntilHandlersIdle();
         activity2.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
                 true, true, false, true, false, false);
         waitUntilHandlersIdle();
         assertNoStartingWindow(activity1);
@@ -2523,7 +2533,7 @@
                     // Surprise, ...! Transfer window in the middle of the creation flow.
                     activity2.addStartingWindow(mPackageName,
                             android.R.style.Theme, null, "Test", 0, 0, 0, 0,
-                            activity1.appToken.asBinder(), true, true, false,
+                            activity1, true, true, false,
                             true, false, false);
                 });
         activity1.addStartingWindow(mPackageName,
@@ -2544,7 +2554,7 @@
                 false, false);
         waitUntilHandlersIdle();
         activity2.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
                 true, true, false, true, false, false);
         waitUntilHandlersIdle();
         assertNoStartingWindow(activity1);
@@ -2600,7 +2610,7 @@
         // Make mVisibleSetFromTransferredStartingWindow true.
         final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
         task.startActivityLocked(middle, null /* focusedTopActivity */,
-                false /* newTask */, false /* keepCurTransition */, null /* options */,
+                false /* newTask */, false /* isTaskSwitch */, null /* options */,
                 null /* sourceRecord */);
         middle.makeFinishingLocked();
 
@@ -2613,7 +2623,7 @@
         top.setVisible(false);
         // The finishing middle should be able to transfer starting window to top.
         task.startActivityLocked(top, null /* focusedTopActivity */,
-                false /* newTask */, false /* keepCurTransition */, null /* options */,
+                false /* newTask */, false /* isTaskSwitch */, null /* options */,
                 null /* sourceRecord */);
 
         assertNull(middle.mStartingWindow);
@@ -2650,7 +2660,7 @@
         // Make sure the fixed rotation transform linked to activity2 when adding starting window
         // on activity2.
         topActivity.addStartingWindow(mPackageName,
-                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity.appToken.asBinder(),
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity,
                 false, false, false, true, false, false);
         waitUntilHandlersIdle();
         assertTrue(topActivity.hasFixedRotationTransform());
@@ -2682,6 +2692,52 @@
     }
 
     @Test
+    public void testStartingWindowInTaskFragment() {
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final WindowState startingWindow = createWindowState(
+                new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1);
+        activity1.addWindow(startingWindow);
+        activity1.attachStartingWindow(startingWindow);
+        activity1.mStartingData = mock(StartingData.class);
+        final Task task = activity1.getTask();
+        final Rect taskBounds = task.getBounds();
+        final int width = taskBounds.width();
+        final int height = taskBounds.height();
+        final BiConsumer<TaskFragment, Rect> fragmentSetup = (fragment, bounds) -> {
+            final Configuration config = fragment.getRequestedOverrideConfiguration();
+            config.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+            config.windowConfiguration.setBounds(bounds);
+            fragment.onRequestedOverrideConfigurationChanged(config);
+        };
+
+        final TaskFragment taskFragment1 = new TaskFragment(
+                mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
+        fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
+        task.addChild(taskFragment1, POSITION_TOP);
+
+        final TaskFragment taskFragment2 = new TaskFragment(
+                mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
+        fragmentSetup.accept(taskFragment2, new Rect(width / 2, 0, width, height));
+        task.addChild(taskFragment2, POSITION_TOP);
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
+        activity2.mVisibleRequested = true;
+        taskFragment2.addChild(activity2);
+        activity1.reparent(taskFragment1, POSITION_TOP);
+
+        assertEquals(task, activity1.mStartingData.mAssociatedTask);
+        assertEquals(taskFragment1.getBounds(), activity1.getBounds());
+        // The activity was resized by task fragment, but starting window must still cover the task.
+        assertEquals(taskBounds, activity1.mStartingWindow.getBounds());
+
+        // The starting window is only removed when all embedded activities are drawn.
+        final WindowState activityWindow = mock(WindowState.class);
+        activity1.onFirstWindowDrawn(activityWindow);
+        assertNotNull(activity1.mStartingWindow);
+        activity2.onFirstWindowDrawn(activityWindow);
+        assertNull(activity1.mStartingWindow);
+    }
+
+    @Test
     public void testTransitionAnimationBounds() {
         removeGlobalMinSizeRestriction();
         final Task task = new TaskBuilder(mSupervisor)
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 2df9a8d..1b4d0a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -32,6 +32,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
@@ -755,12 +756,12 @@
     }
 
     /**
-     * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
-     * move the existing task to front if the current focused stack doesn't have running task.
+     * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will
+     * move the existing task to front if the current focused root task doesn't have running task.
      */
     @Test
-    public void testBringTaskToFrontWhenFocusedStackIsFinising() {
-        // Put 2 tasks in the same stack (simulate the behavior of home stack).
+    public void testBringTaskToFrontWhenFocusedTaskIsFinishing() {
+        // Put 2 tasks in the same root task (simulate the behavior of home root task).
         final Task rootTask = new TaskBuilder(mSupervisor).build();
         final ActivityRecord activity = new ActivityBuilder(mAtm)
                 .setParentTask(rootTask)
@@ -777,13 +778,16 @@
         assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
         finishingTopActivity.finishing = true;
 
-        // Launch the bottom task of the target stack.
+        // Launch the bottom task of the target root task.
         prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
-                .setReason("testBringTaskToFrontWhenTopStackIsFinising")
-                .setIntent(activity.intent)
+                .setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing")
+                .setIntent(activity.intent.addFlags(
+                        FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                 .execute();
+        verify(activity.getRootTask()).startActivityLocked(any(), any(), anyBoolean(),
+                eq(true) /* isTaskSwitch */, any(), any());
         // The hierarchies of the activity should move to front.
-        assertEquals(activity, mRootWindowContainer.topRunningActivity());
+        assertEquals(activity.getTask(), mRootWindowContainer.topRunningActivity().getTask());
     }
 
     /**
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 14d5434..f3bb59c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -50,6 +50,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
@@ -66,6 +67,7 @@
 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.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
@@ -106,9 +108,12 @@
 import android.app.servertransaction.FixedRotationAdjustmentsItem;
 import android.content.res.Configuration;
 import android.graphics.Insets;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.metrics.LogMaker;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -141,6 +146,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -872,19 +879,6 @@
                 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
     }
 
-    @UseTestDisplay
-    @Test
-    public void testClearLastFocusWhenReparentingFocusedWindow() {
-        final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
-        final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
-                defaultDisplay, "window");
-        defaultDisplay.mLastFocus = window;
-        mDisplayContent.mCurrentFocus = window;
-        mDisplayContent.reParentWindowToken(window.mToken);
-
-        assertNull(defaultDisplay.mLastFocus);
-    }
-
     @Test
     public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
         final DisplayContent portraitDisplay = createNewDisplay();
@@ -2204,6 +2198,141 @@
         assertNotEquals(imeChildWindow, mDisplayContent.findFocusedWindow());
     }
 
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testImeMenuDialogFocusWhenImeLayeringTargetChanges() {
+        final WindowState imeMenuDialog =
+                createWindow(mImeWindow, TYPE_INPUT_METHOD_DIALOG, "imeMenuDialog");
+        makeWindowVisibleAndDrawn(imeMenuDialog, mImeWindow);
+        assertTrue(imeMenuDialog.canReceiveKeys());
+        mDisplayContent.setInputMethodWindowLocked(mImeWindow);
+
+        // Verify imeMenuDialog can be focused window if the next IME target requests IME visible.
+        final WindowState imeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
+        mDisplayContent.setImeLayeringTarget(imeAppTarget);
+        spyOn(imeAppTarget);
+        doReturn(true).when(imeAppTarget).getRequestedVisibility(ITYPE_IME);
+        assertEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
+
+        // Verify imeMenuDialog doesn't be focused window if the next IME target does not
+        // request IME visible.
+        final WindowState nextImeAppTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
+        spyOn(nextImeAppTarget);
+        doReturn(true).when(nextImeAppTarget).isAnimating(PARENTS | TRANSITION,
+                ANIMATION_TYPE_APP_TRANSITION);
+        mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
+        assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
+    }
+
+    @Test
+    public void testVirtualDisplayContent() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+        // GIVEN SurfaceControl can successfully mirror the provided surface.
+        Point surfaceSize = new Point(
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        surfaceControlMirrors(surfaceSize);
+
+        // WHEN creating the DisplayContent for a new virtual display.
+        final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+                mDisplayInfo).build();
+
+        // THEN mirroring is initiated for the default display's DisplayArea.
+        assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testVirtualDisplayContent_capturedAreaResized() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+        // GIVEN SurfaceControl can successfully mirror the provided surface.
+        Point surfaceSize = new Point(
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        SurfaceControl mirroredSurface = surfaceControlMirrors(surfaceSize);
+
+        // WHEN creating the DisplayContent for a new virtual display.
+        final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+                mDisplayInfo).build();
+
+        // THEN mirroring is initiated for the default display's DisplayArea.
+        assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+        float xScale = 0.7f;
+        float yScale = 2f;
+        Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
+                Math.round(surfaceSize.y * yScale));
+        virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds);
+
+        // THEN content in the captured DisplayArea is scaled to fit the surface size.
+        verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
+                1.0f / yScale);
+        // THEN captured content is positioned in the centre of the output surface.
+        float scaledWidth = displayAreaBounds.width() / xScale;
+        float xInset = (surfaceSize.x - scaledWidth) / 2;
+        verify(mTransaction, atLeastOnce()).setPosition(mirroredSurface, xInset, 0);
+
+        mockSession.finishMocking();
+    }
+
+    private class TestToken extends Binder {
+    }
+
+    /**
+     * Creates a WindowToken associated with the default task DisplayArea, in order for that
+     * DisplayArea to be mirrored.
+     */
+    private IBinder setUpDefaultTaskDisplayAreaWindowToken() {
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = new TestToken();
+        doReturn(tokenToMirror).when(mWm.mDisplayManagerInternal).getWindowTokenClientToMirror(
+                anyInt());
+
+        // GIVEN the default task display area is represented by the WindowToken.
+        spyOn(mWm.mWindowContextListenerController);
+        doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when(
+                mWm.mWindowContextListenerController).getContainer(any());
+        return tokenToMirror;
+    }
+
+    /**
+     * SurfaceControl successfully creates a mirrored surface of the given size.
+     */
+    private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
+        // Do not set the parent, since the mirrored surface is the root of a new surface hierarchy.
+        SurfaceControl mirroredSurface = new SurfaceControl.Builder()
+                .setName("mirroredSurface")
+                .setBufferSize(surfaceSize.x, surfaceSize.y)
+                .setCallsite("mirrorSurface")
+                .build();
+        doReturn(mirroredSurface).when(() -> SurfaceControl.mirrorSurface(any()));
+        doReturn(surfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
+                anyInt());
+        return mirroredSurface;
+    }
+
     private void removeRootTaskTests(Runnable runnable) {
         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 3c7c4fd..4957ab9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -115,7 +115,7 @@
         spyOn(mNavBarWindow);
 
         // Disabling this call for most tests since it can override the systemUiFlags when called.
-        doReturn(false).when(mDisplayPolicy).updateSystemUiVisibilityLw();
+        doNothing().when(mDisplayPolicy).updateSystemBarAttributes();
 
         updateDisplayFrames();
     }
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 e3c38b0..1b078b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -788,6 +788,19 @@
     }
 
     @Test
+    public void testVisibleEmbeddedTask_expectNotVisible() {
+        Task task = createTaskBuilder(".Task")
+                .setFlags(FLAG_ACTIVITY_NEW_TASK)
+                .build();
+        doReturn(true).when(task).isEmbedded();
+        mRecentTasks.add(task);
+
+        assertThat(mCallbacksRecorder.mAdded).hasSize(1);
+        assertFalse("embedded task should not be visible recents",
+                mRecentTasks.isVisibleRecentTask(task));
+    }
+
+    @Test
     public void testFreezeTaskListOrder_reorderExistingTask() {
         // Add some tasks
         mRecentTasks.add(mTasks.get(0));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 6cc60ea..56d01cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -191,7 +191,6 @@
         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
 
         // Root task removal is deferred if one of its child is animating.
-        doReturn(true).when(rootTask).hasWindowsAlive();
         doReturn(rootTask).when(task).getAnimatingContainer(
                 eq(TRANSITION | CHILDREN), anyInt());
 
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 5989497..3bebf6b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -320,6 +320,11 @@
         assertScaled();
         // Activity is sandboxed due to size compat mode.
         assertActivityMaxBoundsSandboxed();
+
+        final WindowState appWindow = addWindowToActivity(mActivity);
+        assertTrue(mActivity.hasSizeCompatBounds());
+        assertEquals("App window must use size compat bounds for layout in screen space",
+                mActivity.getBounds(), appWindow.getBounds());
     }
 
     @Test
@@ -1981,6 +1986,61 @@
         assertTrue(mActivity.areBoundsLetterboxed());
     }
 
+    /**
+     * Tests that all three paths in which aspect ratio logic can be applied yield the same
+     * result, which is that aspect ratio is respected on app bounds. The three paths are
+     * fixed orientation, no fixed orientation but fixed aspect ratio, and size compat mode.
+     */
+    @Test
+    public void testAllAspectRatioLogicConsistent() {
+        // Create display that has all stable insets and does not rotate. Make sure that status bar
+        // height is greater than notch height so that stable bounds do not equal app bounds.
+        final int notchHeight = 75;
+        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1080, 600)
+                .setSystemDecorations(true).setNotch(notchHeight)
+                .setStatusBarHeight(notchHeight + 20).setCanRotate(false).build();
+
+        // Create task on test display.
+        final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+
+        // Target min aspect ratio must be larger than parent aspect ratio to be applied.
+        final float targetMinAspectRatio = 3.0f;
+
+        // Create fixed portait activity with min aspect ratio greater than parent aspect ratio.
+        final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm)
+                .setTask(task).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .setMinAspectRatio(targetMinAspectRatio).build();
+        final Rect fixedOrientationAppBounds = new Rect(fixedOrientationActivity.getConfiguration()
+                .windowConfiguration.getAppBounds());
+
+        // Create activity with no fixed orientation and min aspect ratio greater than parent aspect
+        // ratio.
+        final ActivityRecord minAspectRatioActivity = new ActivityBuilder(mAtm).setTask(task)
+                .setMinAspectRatio(targetMinAspectRatio).build();
+        final Rect minAspectRatioAppBounds = new Rect(minAspectRatioActivity.getConfiguration()
+                .windowConfiguration.getAppBounds());
+
+        // Create unresizeable fixed portait activity with min aspect ratio greater than parent
+        // aspect ratio.
+        final ActivityRecord sizeCompatActivity = new ActivityBuilder(mAtm)
+                .setTask(task).setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+                .setMinAspectRatio(targetMinAspectRatio).build();
+        // Resize display running unresizeable activity to make it enter size compat mode.
+        resizeDisplay(display, 1800, 1000);
+        final Rect sizeCompatAppBounds = new Rect(sizeCompatActivity.getConfiguration()
+                .windowConfiguration.getAppBounds());
+
+        // Check that aspect ratio of app bounds is equal to the min aspect ratio.
+        final float delta = 0.01f;
+        assertEquals(targetMinAspectRatio, ActivityRecord
+                .computeAspectRatio(fixedOrientationAppBounds), delta);
+        assertEquals(targetMinAspectRatio, ActivityRecord
+                .computeAspectRatio(minAspectRatioAppBounds), delta);
+        assertEquals(targetMinAspectRatio, ActivityRecord
+                .computeAspectRatio(sizeCompatAppBounds), delta);
+    }
+
     private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
             float letterboxHorizontalPositionMultiplier) {
         // Set up a display in landscape and ignoring orientation request.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 629e452..8074944 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -126,8 +126,15 @@
         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
 
-        task.removeIfPossible();
-        // Assert that the container was removed.
+        task.remove(false /* withTransition */, "testRemoveContainer");
+        // There is still an activity to be destroyed, so the task is not removed immediately.
+        assertNotNull(task.getParent());
+        assertTrue(rootTask.hasChild());
+        assertTrue(task.hasChild());
+        assertTrue(activity.finishing);
+
+        activity.destroyed("testRemoveContainer");
+        // Assert that the container was removed after the activity is destroyed.
         assertNull(task.getParent());
         assertEquals(0, task.getChildCount());
         assertNull(activity.getParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index ce2d748..061a4c5f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -19,7 +19,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -77,6 +79,7 @@
         private int mPosition = POSITION_BOTTOM;
         protected final ActivityTaskManagerService mService;
         private boolean mSystemDecorations = false;
+        private int mStatusBarHeight = 0;
 
         Builder(ActivityTaskManagerService service, int width, int height) {
             mService = service;
@@ -125,6 +128,10 @@
                     Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null);
             return this;
         }
+        Builder setStatusBarHeight(int height) {
+            mStatusBarHeight = height;
+            return this;
+        }
         Builder setCanRotate(boolean canRotate) {
             mCanRotate = canRotate;
             return this;
@@ -153,11 +160,20 @@
             if (mSystemDecorations) {
                 doReturn(true).when(newDisplay).supportsSystemDecorations();
                 doReturn(true).when(displayPolicy).hasNavigationBar();
+                doReturn(20).when(displayPolicy).getNavigationBarHeight(anyInt(), anyInt());
             } else {
                 doReturn(false).when(displayPolicy).hasNavigationBar();
                 doReturn(false).when(displayPolicy).hasStatusBar();
                 doReturn(false).when(newDisplay).supportsSystemDecorations();
             }
+            if (mStatusBarHeight > 0) {
+                doReturn(true).when(displayPolicy).hasStatusBar();
+                doAnswer(invocation -> {
+                    Rect inOutInsets = (Rect) invocation.getArgument(0);
+                    inOutInsets.top = mStatusBarHeight;
+                    return null;
+                }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt());
+            }
             Configuration c = new Configuration();
             newDisplay.computeScreenConfiguration(c);
             c.windowConfiguration.setWindowingMode(mWindowingMode);
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 39fe952..9160109 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -81,6 +81,7 @@
 import android.window.IWindowContainerTransactionCallback;
 import android.window.StartingWindowInfo;
 import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
 import androidx.test.filters.SmallTest;
@@ -1275,6 +1276,24 @@
         assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch());
     }
 
+    @Test
+    public void testResumeTopsWhenLeavingPinned() {
+        final ActivityRecord record = makePipableActivity();
+        final Task rootTask = record.getRootTask();
+
+        clearInvocations(mWm.mAtmService.mRootWindowContainer);
+        final WindowContainerTransaction t = new WindowContainerTransaction();
+        WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken();
+        t.setWindowingMode(wct, WINDOWING_MODE_PINNED);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+
+        clearInvocations(mWm.mAtmService.mRootWindowContainer);
+        t.setWindowingMode(wct, WINDOWING_MODE_FULLSCREEN);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+    }
+
     /**
      * Verifies that task vanished is called for a specific task.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index aa56183..17288c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -53,9 +53,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -895,36 +892,6 @@
         assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
     }
 
-    @UseTestDisplay(addWindows = W_INPUT_METHOD)
-    @Test
-    public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() {
-        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
-        final InsetsStateController controller = mDisplayContent.getInsetsStateController();
-        controller.getImeSourceProvider().setWindow(mImeWindow, null, null);
-
-        // Simulate app requests IME with updating all windows Insets State when IME is above app.
-        mDisplayContent.setImeLayeringTarget(app);
-        mDisplayContent.setImeInputTarget(app);
-        assertTrue(mDisplayContent.shouldImeAttachedToApp());
-        controller.getImeSourceProvider().scheduleShowImePostLayout(app);
-        controller.getImeSourceProvider().getSource().setVisible(true);
-        controller.updateAboveInsetsState(mImeWindow, false);
-
-        // Simulate task switching animation happens when switching app to app2.
-        spyOn(app);
-        spyOn(app2);
-        doReturn(true).when(app).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS);
-        doReturn(true).when(app2).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS);
-        app.mActivityRecord.mLastImeShown = true;
-
-        // Verify the IME insets is visible on app, but not for app2 during task animating.
-        InsetsState stateApp = app.getInsetsState();
-        InsetsState stateApp2 = app2.getInsetsState();
-        assertTrue(stateApp.getSource(ITYPE_IME).isVisible());
-        assertFalse(stateApp2.getSource(ITYPE_IME).isVisible());
-    }
-
     @UseTestDisplay(addWindows = { W_ACTIVITY })
     @Test
     public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index 5874b4b..7b6ccd3 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -25,12 +25,12 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager.Sensors;
+import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.usb.AccessoryFilter;
 import android.hardware.usb.DeviceFilter;
 import android.hardware.usb.UsbAccessory;
-import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -52,9 +52,9 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.server.LocalServices;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -64,7 +64,6 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 
 /**
  * UsbUserPermissionManager manages usb device or accessory access permissions.
@@ -110,19 +109,20 @@
      */
     @GuardedBy("mLock")
     private boolean mIsCopyPermissionsScheduled;
+    private final SensorPrivacyManagerInternal mSensorPrivacyMgrInternal;
 
     UsbUserPermissionManager(@NonNull Context context,
             @NonNull UsbUserSettingsManager usbUserSettingsManager) {
         mContext = context;
         mUser = context.getUser();
         mUsbUserSettingsManager = usbUserSettingsManager;
+        mSensorPrivacyMgrInternal = LocalServices.getService(SensorPrivacyManagerInternal.class);
         mDisablePermissionDialogs = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_disableUsbPermissionDialogs);
 
         mPermissionsFile = new AtomicFile(new File(
                 Environment.getUserSystemDirectory(mUser.getIdentifier()),
                 "usb_permissions.xml"), "usb-permissions");
-
         synchronized (mLock) {
             readPermissionsLocked();
         }
@@ -195,11 +195,27 @@
      */
     boolean hasPermission(@NonNull UsbDevice device, @NonNull String packageName, int pid,
             int uid) {
-        if (isCameraDevicePresent(device)) {
-            if (!isCameraPermissionGranted(packageName, pid, uid)) {
+        if (device.getHasVideoCapture()) {
+            boolean isCameraPrivacyEnabled = mSensorPrivacyMgrInternal.isSensorPrivacyEnabled(
+                    UserHandle.getUserId(uid), Sensors.CAMERA);
+            if (DEBUG) {
+                Slog.d(TAG, "isCameraPrivacyEnabled: " + isCameraPrivacyEnabled);
+            }
+            if (isCameraPrivacyEnabled || !isCameraPermissionGranted(packageName, pid, uid)) {
                 return false;
             }
         }
+        // Only check for microphone privacy and not RECORD_AUDIO permission, because access to usb
+        // camera device with audio recording capabilities may still be granted with a warning
+        if (device.getHasAudioCapture() && mSensorPrivacyMgrInternal.isSensorPrivacyEnabled(
+                UserHandle.getUserId(uid), Sensors.MICROPHONE)) {
+            if (DEBUG) {
+                Slog.d(TAG,
+                        "Access to device with audio recording capabilities denied because "
+                                + "microphone privacy is enabled.");
+            }
+            return false;
+        }
         synchronized (mLock) {
             if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
                 return true;
@@ -698,7 +714,10 @@
             }
             return;
         }
-        if (isCameraDevicePresent(device)) {
+        // If the app doesn't have camera permission do not request permission to the USB device.
+        // Note that if the USB camera also has a microphone, a warning will be shown to the user if
+        // the app doesn't have RECORD_AUDIO permission.
+        if (device.getHasVideoCapture()) {
             if (!isCameraPermissionGranted(packageName, pid, uid)) {
                 intent.putExtra(UsbManager.EXTRA_DEVICE, device);
                 intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
@@ -733,27 +752,4 @@
         requestPermissionDialog(null, accessory,
                 mUsbUserSettingsManager.canBeDefault(accessory, packageName), packageName, pi, uid);
     }
-
-    /**
-     * Check whether a particular device or any of its interfaces
-     * is of class VIDEO.
-     *
-     * @param device The device that needs to get scanned
-     * @return True in case a VIDEO device or interface is present,
-     * False otherwise.
-     */
-    private boolean isCameraDevicePresent(UsbDevice device) {
-        if (device.getDeviceClass() == UsbConstants.USB_CLASS_VIDEO) {
-            return true;
-        }
-
-        for (int i = 0; i < device.getInterfaceCount(); i++) {
-            UsbInterface iface = device.getInterface(i);
-            if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VIDEO) {
-                return true;
-            }
-        }
-
-        return false;
-    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 965f126..734172f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -36,6 +36,7 @@
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
+import android.media.AudioManagerInternal;
 import android.media.permission.Identity;
 import android.media.permission.PermissionUtil;
 import android.os.Binder;
@@ -44,6 +45,7 @@
 import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SharedMemory;
@@ -275,6 +277,7 @@
             LocalServices.getService(PermissionManagerServiceInternal.class)
                     .setHotwordDetectionServiceProvider(null);
             mIdentity = null;
+            updateServiceUidForAudioPolicy(Process.INVALID_UID);
         }
         mCancellationTaskFuture.cancel(/* may interrupt */ true);
         if (mAudioFlinger != null) {
@@ -893,6 +896,8 @@
         connection.run(service -> service.ping(new IRemoteCallback.Stub() {
             @Override
             public void sendResult(Bundle bundle) throws RemoteException {
+                // TODO: Exit if the service has been unbound already (though there's a very low
+                // chance this happens).
                 if (DEBUG) {
                     Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
                 }
@@ -902,10 +907,21 @@
                 LocalServices.getService(PermissionManagerServiceInternal.class)
                         .setHotwordDetectionServiceProvider(() -> uid);
                 mIdentity = new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
+                updateServiceUidForAudioPolicy(uid);
             }
         }));
     }
 
+    private void updateServiceUidForAudioPolicy(int uid) {
+        mScheduledExecutorService.execute(() -> {
+            final AudioManagerInternal audioManager =
+                    LocalServices.getService(AudioManagerInternal.class);
+            if (audioManager != null) {
+                audioManager.setHotwordDetectionServiceUid(uid);
+            }
+        });
+    }
+
     private static void bestEffortClose(Closeable closeable) {
         try {
             closeable.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
index b9e1fcd..c0c3e6f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
@@ -29,7 +29,6 @@
 import android.media.permission.PermissionUtil;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.ServiceSpecificException;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -61,7 +60,7 @@
 
     @Override
     public SoundTrigger.ModuleProperties getDspModuleProperties() throws RemoteException {
-        // No permission needed.
+        // No permission needed here (the app must have the Assistant Role to retrieve the session).
         return mDelegate.getDspModuleProperties();
     }
 
@@ -72,7 +71,9 @@
         if (DEBUG) {
             Slog.d(TAG, "startRecognition");
         }
-        enforcePermissions();
+        if (!isHoldingPermissions()) {
+            return SoundTrigger.STATUS_PERMISSION_DENIED;
+        }
         return mDelegate.startRecognition(i, s, iHotwordRecognitionStatusCallback,
                 recognitionConfig, b);
     }
@@ -81,25 +82,28 @@
     public int stopRecognition(int i,
             IHotwordRecognitionStatusCallback iHotwordRecognitionStatusCallback)
             throws RemoteException {
-        enforcePermissions();
+        // Stopping a model does not require special permissions. Having a handle to the session is
+        // sufficient.
         return mDelegate.stopRecognition(i, iHotwordRecognitionStatusCallback);
     }
 
     @Override
     public int setParameter(int i, int i1, int i2) throws RemoteException {
-        enforcePermissions();
+        if (!isHoldingPermissions()) {
+            return SoundTrigger.STATUS_PERMISSION_DENIED;
+        }
         return mDelegate.setParameter(i, i1, i2);
     }
 
     @Override
     public int getParameter(int i, int i1) throws RemoteException {
-        enforcePermissions();
+        // No permission needed here (the app must have the Assistant Role to retrieve the session).
         return mDelegate.getParameter(i, i1);
     }
 
     @Override
     public SoundTrigger.ModelParamRange queryParameter(int i, int i1) throws RemoteException {
-        enforcePermissions();
+        // No permission needed here (the app must have the Assistant Role to retrieve the session).
         return mDelegate.queryParameter(i, i1);
     }
 
@@ -110,15 +114,21 @@
     }
 
     // TODO: Share this code with SoundTriggerMiddlewarePermission.
-    private void enforcePermissions() {
-        enforcePermissionForPreflight(mContext, mOriginatorIdentity, RECORD_AUDIO);
-        enforcePermissionForPreflight(mContext, mOriginatorIdentity, CAPTURE_AUDIO_HOTWORD);
+    private boolean isHoldingPermissions() {
+        try {
+            enforcePermissionForPreflight(mContext, mOriginatorIdentity, RECORD_AUDIO);
+            enforcePermissionForPreflight(mContext, mOriginatorIdentity, CAPTURE_AUDIO_HOTWORD);
+            return true;
+        } catch (SecurityException e) {
+            Slog.e(TAG, e.toString());
+            return false;
+        }
     }
 
     /**
      * Throws a {@link SecurityException} if originator permanently doesn't have the given
-     * permission, or a {@link ServiceSpecificException} with a {@link
-     * #TEMPORARY_PERMISSION_DENIED} if caller originator doesn't have the given permission.
+     * permission.
+     * Soft (temporary) denials are considered OK for preflight purposes.
      *
      * @param context    A {@link Context}, used for permission checks.
      * @param identity   The identity to check.
@@ -130,15 +140,12 @@
                 permission);
         switch (status) {
             case PermissionChecker.PERMISSION_GRANTED:
+            case PermissionChecker.PERMISSION_SOFT_DENIED:
                 return;
             case PermissionChecker.PERMISSION_HARD_DENIED:
                 throw new SecurityException(
                         TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
                                 permission, toString(identity)));
-            case PermissionChecker.PERMISSION_SOFT_DENIED:
-                throw new ServiceSpecificException(TEMPORARY_PERMISSION_DENIED,
-                        TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
-                                permission, toString(identity)));
             default:
                 throw new RuntimeException("Unexpected permission check result.");
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 71541ad..9ea2b7b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1896,17 +1896,19 @@
 
                         String serviceComponentName = serviceInfo.getComponentName()
                                 .flattenToShortString();
-
-                        String serviceRecognizerName = new ComponentName(pkg,
-                                voiceInteractionServiceInfo.getRecognitionService())
-                                .flattenToShortString();
+                        if (voiceInteractionServiceInfo.getRecognitionService() == null) {
+                            Slog.e(TAG, "The RecognitionService must be set to avoid boot "
+                                    + "loop on earlier platform version. Also make sure that this "
+                                    + "is a valid RecognitionService when running on Android 11 "
+                                    + "or earlier.");
+                            serviceComponentName = "";
+                        }
 
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.ASSISTANT, serviceComponentName, userId);
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
                                 userId);
-
                         return;
                     }
 
@@ -1947,6 +1949,29 @@
             }
         }
 
+        private void resetServicesIfNoRecognitionService(ComponentName serviceComponent,
+                int userHandle) {
+            for (ResolveInfo resolveInfo : queryInteractorServices(userHandle,
+                    serviceComponent.getPackageName())) {
+                VoiceInteractionServiceInfo serviceInfo =
+                        new VoiceInteractionServiceInfo(
+                                mContext.getPackageManager(),
+                                resolveInfo.serviceInfo);
+                if (!serviceInfo.getSupportsAssist()) {
+                    continue;
+                }
+                if (serviceInfo.getRecognitionService() == null) {
+                    Slog.e(TAG, "The RecognitionService must be set to "
+                            + "avoid boot loop on earlier platform version. "
+                            + "Also make sure that this is a valid "
+                            + "RecognitionService when running on Android 11 "
+                            + "or earlier.");
+                    setCurInteractor(null, userHandle);
+                    resetCurAssistant(userHandle);
+                }
+            }
+        }
+
         PackageMonitor mPackageMonitor = new PackageMonitor() {
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
@@ -2090,6 +2115,7 @@
 
                         change = isPackageAppearing(curInteractor.getPackageName());
                         if (change != PACKAGE_UNCHANGED) {
+                            resetServicesIfNoRecognitionService(curInteractor, userHandle);
                             // If current interactor is now appearing, for any reason, then
                             // restart our connection with it.
                             if (mImpl != null && curInteractor.getPackageName().equals(
@@ -2112,6 +2138,13 @@
                             initForUser(userHandle);
                             return;
                         }
+                        change = isPackageAppearing(curAssistant.getPackageName());
+                        if (change != PACKAGE_UNCHANGED) {
+                            // It is possible to update Assistant without a voice interactor to one
+                            // with a voice-interactor. We should make sure the recognition service
+                            // is set to avoid boot loop.
+                            resetServicesIfNoRecognitionService(curAssistant, userHandle);
+                        }
                     }
 
                     // There is no interactor, so just deal with a simple recognizer.
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e000265..abbce1c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -2430,7 +2430,8 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.isIncomingCallPermitted(phoneAccountHandle);
+                return service.isIncomingCallPermitted(phoneAccountHandle,
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error isIncomingCallPermitted", e);
             }
@@ -2463,7 +2464,8 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.isOutgoingCallPermitted(phoneAccountHandle);
+                return service.isOutgoingCallPermitted(phoneAccountHandle,
+                        mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.e(TAG, "Error isOutgoingCallPermitted", e);
             }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 6f286d9..a75f79c 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -306,12 +306,14 @@
     /**
      * @see TelecomServiceImpl#isIncomingCallPermitted
      */
-    boolean isIncomingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+    boolean isIncomingCallPermitted(in PhoneAccountHandle phoneAccountHandle,
+            String callingPackage);
 
     /**
      * @see TelecomServiceImpl#isOutgoingCallPermitted
      */
-    boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+    boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle,
+            String callingPackage);
 
     /**
      * @see TelecomServiceImpl#waitOnHandler
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 628c480..4df8a4b 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -4,13 +4,14 @@
 breadley@google.com
 fionaxu@google.com
 jackyu@google.com
-hallliu@google.com
 rgreenwalt@google.com
 tgunn@google.com
 jminjie@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
 xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp
index 201ab53..1cacc03 100644
--- a/telephony/common/Android.bp
+++ b/telephony/common/Android.bp
@@ -19,6 +19,14 @@
     ],
 }
 
+filegroup {
+    name: "framework-mms-shared-srcs",
+    visibility: ["//packages/apps/Bluetooth"],
+    srcs: [
+        "com/google/android/mms/**/*.java",
+    ],
+}
+
 genrule {
     name: "statslog-telephony-common-java-gen",
     tools: ["stats-log-api-gen"],
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8e910c9..0e4c44e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -490,6 +490,12 @@
     /** Used in Cellular Network Settings for preferred network type. */
     public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
 
+    /**
+     * Used in Cellular Network Settings for preferred network type to show 4G only mode.
+     * @hide
+     */
+    public static final String KEY_4G_ONLY_BOOL = "4g_only_bool";
+
     /** Show cdma network mode choices 1x, 3G, global etc. */
     public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
 
@@ -5257,6 +5263,7 @@
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
         sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+        sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
         sDefaults.putBoolean(KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL, false);
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index c18ab33..f004824 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -193,6 +193,10 @@
         return mDelegateBinder;
     }
 
+    public ISipDelegateStateCallback getStateCallbackBinder() {
+        return mStateBinder;
+    }
+
     private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
         String transactionId = m.getViaBranchParameter();
         SipDelegate d = mDelegate;
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 1f74c09..13ea9973 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -21,6 +21,7 @@
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.telephony.ims.DelegateMessageCallback;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.DelegateStateCallback;
@@ -33,6 +34,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -49,10 +51,15 @@
 public class SipTransportImplBase {
     private static final String LOG_TAG = "SipTransportIB";
 
-    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+    private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
         public void binderDied() {
-            mBinderExecutor.execute(() -> binderDiedInternal());
+            // Clean up all binders in this case.
+            mBinderExecutor.execute(() -> binderDiedInternal(null));
+        }
+        @Override
+        public void binderDied(IBinder who) {
+            mBinderExecutor.execute(() -> binderDiedInternal(who));
         }
     };
 
@@ -142,6 +149,7 @@
             ISipDelegateStateCallback cb, ISipDelegateMessageCallback mc) {
         SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc);
         mDelegates.add(wrapper);
+        linkDeathRecipient(wrapper);
         createSipDelegate(subId, r, wrapper, wrapper);
     }
 
@@ -155,6 +163,7 @@
         }
 
         if (result != null) {
+            unlinkDeathRecipient(result);
             mDelegates.remove(result);
             destroySipDelegate(result.getDelegate(), reason);
         } else {
@@ -163,12 +172,37 @@
         }
     }
 
-    private void binderDiedInternal() {
-        for (SipDelegateAidlWrapper w : mDelegates) {
-            destroySipDelegate(w.getDelegate(),
-                    SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+    private void linkDeathRecipient(SipDelegateAidlWrapper w) {
+        try {
+            w.getStateCallbackBinder().asBinder().linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "linkDeathRecipient, remote process already died, cleaning up.");
+            mDeathRecipient.binderDied(w.getStateCallbackBinder().asBinder());
         }
-        mDelegates.clear();
+    }
+
+    private void unlinkDeathRecipient(SipDelegateAidlWrapper w) {
+        try {
+            w.getStateCallbackBinder().asBinder().unlinkToDeath(mDeathRecipient, 0);
+        } catch (NoSuchElementException e) {
+            // Ignore this case.
+        }
+    }
+
+    private void binderDiedInternal(IBinder who) {
+        for (SipDelegateAidlWrapper w : mDelegates) {
+            // If the binder itself was not given from the platform, just clean up all binders.
+            if (who == null || w.getStateCallbackBinder().asBinder().equals(who))  {
+                Log.w(LOG_TAG, "Binder death detected for " + w + ", calling destroy and "
+                        + "removing.");
+                mDelegates.remove(w);
+                destroySipDelegate(w.getDelegate(),
+                        SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+                return;
+            }
+        }
+        Log.w(LOG_TAG, "Binder death detected for IBinder " + who + ", but couldn't find matching "
+                + "SipDelegate");
     }
 
     /**
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 4ecca2d..cf56586 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -31,6 +31,8 @@
     private static final String SYSTEM_SERVER_PROFILE =
             "/data/misc/profiles/cur/0/android/primary.prof";
     private static final boolean USE_PHENOTYPE = false;
+    private static final String DALVIK_VM_EXTRA_OPTS =
+            "-Xusejit:false -Xint -Xjitsaveprofilinginfo";
 
     @Override
     public void setDevice(ITestDevice testDevice) {
@@ -54,10 +56,10 @@
     private String setProperty(String property, String value) throws Exception {
         if (USE_PHENOTYPE) {
             return mTestDevice.executeShellCommand(
-                "device_config put runtime_native_boot " + property + " " + value);
+                String.format("device_config put runtime_native_boot %s '%s'", property, value));
         } else {
             return mTestDevice.executeShellCommand(
-                "setprop dalvik.vm." + property + " " + value);
+                String.format("setprop dalvik.vm.%s '%s'", property, value));
         }
     }
 
@@ -69,6 +71,8 @@
         assertTrue("profile boot class path not enabled: " + res, "true".equals(res));
         res = getProperty("profilesystemserver");
         assertTrue("profile system server not enabled: " + res, "true".equals(res));
+        res = getProperty("extra-opts");
+        assertTrue("extra options not set: " + res, DALVIK_VM_EXTRA_OPTS.equals(res));
     }
 
     private boolean forceSaveProfile(String pkg) throws Exception {
@@ -91,16 +95,20 @@
             boolean profileBootClassPath = "true".equals(pbcp);
             String pss = getProperty("profilesystemserver");
             boolean profileSystemServer = "true".equals(pss);
-            if (profileBootClassPath && profileSystemServer) {
+            String extraOpts = getProperty("extra-opts");
+            boolean extraOptsOk = DALVIK_VM_EXTRA_OPTS.equals(extraOpts);
+            if (profileBootClassPath && profileSystemServer && extraOptsOk) {
                 break;
             }
             if (i == numIterations) {
                 assertTrue("profile system server not enabled: " + pss, profileSystemServer);
                 assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
+                assertTrue("extra options not set: " + extraOpts, extraOptsOk);
             }
 
             setProperty("profilebootclasspath", "true");
             setProperty("profilesystemserver", "true");
+            setProperty("extra-opts", DALVIK_VM_EXTRA_OPTS);
             Thread.sleep(1000);
         }
 
@@ -114,12 +122,15 @@
             boolean profileBootClassPath = "true".equals(pbcp);
             String pss = getProperty("profilesystemserver");
             boolean profileSystemServer = "true".equals(pss);
+            String extraOpts = getProperty("extra-opts");
+            boolean extraOptsOk = DALVIK_VM_EXTRA_OPTS.equals(extraOpts);
             if (profileBootClassPath && profileSystemServer) {
                 break;
             }
             if (i == numIterations) {
                 assertTrue("profile system server not enabled: " + pss, profileSystemServer);
                 assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
+                assertTrue("extra options not set: " + extraOpts, extraOptsOk);
             }
             Thread.sleep(1000);
         }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
new file mode 100644
index 0000000..3074e28
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class NonResizeableAppHelper @JvmOverloads constructor(
+    instr: Instrumentation,
+    launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME,
+    component: ComponentName = ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME,
+    launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+        .getInstance(instr)
+        .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
new file mode 100644
index 0000000..19fefb9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class TwoActivitiesAppHelper @JvmOverloads constructor(
+    instr: Instrumentation,
+    launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME,
+    component: ComponentName = ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME,
+    launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+        .getInstance(instr)
+        .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
+        val button = device.wait(
+                Until.findObject(By.res(getPackage(), "launch_second_activity")),
+                FIND_TIMEOUT)
+
+        require(button != null) {
+            "Button not found, this usually happens when the device " +
+                    "was left in an unknown state (e.g. in split screen)"
+        }
+        button.click()
+        wmHelper.waitForAppTransitionIdle()
+        wmHelper.waitForFullScreenApp(component)
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
new file mode 100644
index 0000000..a21eae8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the back and forward transition between 2 activities.
+ * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            withTestName { testSpec.name }
+            repeat { testSpec.config.repetitions }
+            setup {
+                eachRun {
+                    testApp.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(testApp.component)
+                }
+            }
+            teardown {
+                test {
+                    testApp.exit()
+                }
+            }
+            transitions {
+                testApp.openSecondActivity(device, wmHelper)
+                device.pressBack()
+                wmHelper.waitForAppTransitionIdle()
+                wmHelper.waitForFullScreenApp(testApp.component)
+            }
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun finishSubActivity() {
+        testSpec.assertWm {
+            this.isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+                    .then()
+                    .isAppWindowOnTop(ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME)
+                    .then()
+                    .isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun entireScreenCovered() {
+        testSpec.entireScreenCovered(testSpec.config.startRotation)
+    }
+
+    @Presubmit
+    @Test
+    fun launcherWindowNotVisible() {
+        testSpec.assertWm {
+            this.isAppWindowInvisible(LAUNCHER_COMPONENT, ignoreActivity = true)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun launcherLayerNotVisible() {
+        testSpec.assertLayers { this.isInvisible(LAUNCHER_COMPONENT) }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(repetitions = 5)
+        }
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
new file mode 100644
index 0000000..7077d3b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app while the phone is locked
+ * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+    override val testApp = NonResizeableAppHelper(instrumentation)
+
+    override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+        get() = {
+            super.transition(this, it)
+            setup {
+                eachRun {
+                    device.sleep()
+                    wmHelper.waitForAppTransitionIdle()
+                }
+            }
+            teardown {
+                eachRun {
+                    testApp.exit(wmHelper)
+                }
+            }
+            transitions {
+                testApp.launchViaIntent(wmHelper)
+                wmHelper.waitForFullScreenApp(testApp.component)
+            }
+        }
+
+    @Presubmit
+    @Test
+    override fun navBarLayerIsVisible() {
+        testSpec.assertLayersEnd {
+            isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun nonResizableAppLayerBecomesVisible() {
+        testSpec.assertLayers {
+            this.notContains(testApp.component)
+                    .then()
+                    .isInvisible(testApp.component)
+                    .then()
+                    .isVisible(testApp.component)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun nonResizableAppWindowBecomesVisible() {
+        testSpec.assertWm {
+            this.notContains(testApp.component)
+                    .then()
+                    .isAppWindowInvisible(testApp.component,
+                            ignoreActivity = true, isOptional = true)
+                    .then()
+                    .isAppWindowVisible(testApp.component, ignoreActivity = true)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun nonResizableAppWindowBecomesVisibleAtEnd() {
+        testSpec.assertWmEnd {
+            this.isVisible(testApp.component)
+        }
+    }
+
+    @FlakyTest
+    @Test
+    override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+
+    @FlakyTest
+    @Test
+    override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+    @FlakyTest
+    @Test
+    override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
+
+    @FlakyTest
+    @Test
+    override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+    @FlakyTest
+    @Test
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+            super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+    @FlakyTest
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+            super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+    @FlakyTest
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
+    @FlakyTest
+    @Test
+    override fun focusChanges() = super.focusChanges()
+
+    @FlakyTest
+    @Test
+    override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+    @FlakyTest
+    @Test
+    override fun appWindowReplacesLauncherAsTopWindow() =
+            super.appWindowReplacesLauncherAsTopWindow()
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(
+                            repetitions = 5,
+                            supportedNavigationModes =
+                            listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
+                            supportedRotations = listOf(Surface.ROTATION_0)
+                    )
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 860a5ae..1435120 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -44,7 +44,7 @@
 
 abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-    protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+    protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
 
     protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
         withTestName { testSpec.name }
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 1599ed4..3b9f33a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -59,5 +59,26 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".NonResizeableActivity"
+            android:resizeableActivity="false"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
+            android:label="NonResizeableApp"
+            android:exported="true"
+            android:showOnLockScreen="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".ButtonActivity"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.ButtonActivity"
+            android:configChanges="orientation|screenSize"
+            android:label="ButtonActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
new file mode 100644
index 0000000..fe7bced
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/holo_orange_light">
+    <Button
+        android:id="@+id/launch_second_activity"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Second activity" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
new file mode 100644
index 0000000..6d5a9dd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="@android:color/holo_orange_light">
+
+  <TextView
+      android:id="@+id/NonResizeableTest"
+      android:layout_width="fill_parent"
+      android:layout_height="fill_parent"
+      android:gravity="center_vertical|center_horizontal"
+      android:text="NonResizeableActivity"
+      android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 0ccc498..224d2ac 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -41,4 +41,14 @@
     public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
             new ComponentName(FLICKER_APP_PACKAGE,
                     FLICKER_APP_PACKAGE + ".SimpleActivity");
+
+    public static final String NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME = "NonResizeableApp";
+    public static final ComponentName NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                    FLICKER_APP_PACKAGE + ".NonResizeableActivity");
+
+    public static final String BUTTON_ACTIVITY_LAUNCHER_NAME = "ButtonApp";
+    public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                    FLICKER_APP_PACKAGE + ".ButtonActivity");
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
new file mode 100644
index 0000000..b42ac2a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.flicker.testapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class ButtonActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        WindowManager.LayoutParams p = getWindow().getAttributes();
+        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        getWindow().setAttributes(p);
+        setContentView(R.layout.activity_button);
+
+        Button button = findViewById(R.id.launch_second_activity);
+        button.setOnClickListener(v -> {
+            Intent intent = new Intent(ButtonActivity.this, SimpleActivity.class);
+            startActivity(intent);
+        });
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
new file mode 100644
index 0000000..61019d8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+
+public class NonResizeableActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.activity_non_resizeable);
+
+        setShowWhenLocked(true);
+        setTurnScreenOn(true);
+        KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+        if (keyguardManager != null) {
+            keyguardManager.requestDismissKeyguard(this, null);
+        }
+    }
+}
diff --git a/tests/InputMethodStressTest/Android.bp b/tests/InputMethodStressTest/Android.bp
new file mode 100644
index 0000000..131611d
--- /dev/null
+++ b/tests/InputMethodStressTest/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "InputMethodStressTest",
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner"],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "androidx.test.uiautomator_uiautomator",
+        "compatibility-device-util-axt",
+        "platform-test-annotations",
+        "truth-prebuilt",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    sdk_version: "31",
+}
diff --git a/tests/InputMethodStressTest/AndroidManifest.xml b/tests/InputMethodStressTest/AndroidManifest.xml
new file mode 100644
index 0000000..e5d6518
--- /dev/null
+++ b/tests/InputMethodStressTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.inputmethod.stresstest">
+
+    <application>
+        <activity android:name=".TestActivity"/>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="com.android.inputmethod.stresstest">
+    </instrumentation>
+</manifest>
diff --git a/tests/InputMethodStressTest/AndroidTest.xml b/tests/InputMethodStressTest/AndroidTest.xml
new file mode 100644
index 0000000..b194010
--- /dev/null
+++ b/tests/InputMethodStressTest/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="InputMethod integration/regression test">
+    <option name="test-suite-tag" value="apct" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="InputMethodStressTest.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.inputmethod.stresstest" />
+    </test>
+</configuration>
diff --git a/tests/InputMethodStressTest/OWNERS b/tests/InputMethodStressTest/OWNERS
new file mode 100644
index 0000000..6bb4b17
--- /dev/null
+++ b/tests/InputMethodStressTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 34867
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java
new file mode 100644
index 0000000..5427fd8
--- /dev/null
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/ImeOpenCloseStressTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.stresstest;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.platform.test.annotations.RootPermissionTest;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RootPermissionTest
+@RunWith(AndroidJUnit4.class)
+public class ImeOpenCloseStressTest {
+
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
+    private static final int NUM_TEST_ITERATIONS = 100;
+
+    private Instrumentation mInstrumentation;
+
+    @Test
+    public void test() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        Intent intent = new Intent()
+                .setAction(Intent.ACTION_MAIN)
+                .setClass(mInstrumentation.getContext(), TestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        TestActivity activity = (TestActivity) mInstrumentation.startActivitySync(intent);
+        eventually(() -> assertThat(callOnMainSync(activity::hasWindowFocus)).isTrue(), TIMEOUT);
+        for (int i = 0; i < NUM_TEST_ITERATIONS; i++) {
+            mInstrumentation.runOnMainSync(activity::showIme);
+            eventually(() -> assertThat(callOnMainSync(activity::isImeShown)).isTrue(), TIMEOUT);
+            mInstrumentation.runOnMainSync(activity::hideIme);
+            eventually(() -> assertThat(callOnMainSync(activity::isImeShown)).isFalse(), TIMEOUT);
+        }
+    }
+
+    private <V> V callOnMainSync(Callable<V> callable) {
+        AtomicReference<V> result = new AtomicReference<>();
+        AtomicReference<Exception> thrownException = new AtomicReference<>();
+        mInstrumentation.runOnMainSync(() -> {
+            try {
+                result.set(callable.call());
+            } catch (Exception e) {
+                thrownException.set(e);
+            }
+        });
+        if (thrownException.get() != null) {
+            throw new RuntimeException("Exception thrown from Main thread", thrownException.get());
+        }
+        return result.get();
+    }
+}
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java b/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java
new file mode 100644
index 0000000..7baf037
--- /dev/null
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/TestActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.stresstest;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowInsets;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+
+public class TestActivity extends Activity {
+
+    private EditText mEditText;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        LinearLayout rootView = new LinearLayout(this);
+        rootView.setOrientation(LinearLayout.VERTICAL);
+        mEditText = new EditText(this);
+        rootView.addView(mEditText, new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
+        setContentView(rootView);
+    }
+
+    public boolean hasWindowFocus() {
+        return mEditText.hasWindowFocus();
+    }
+
+    public boolean isImeShown() {
+        WindowInsets insets = mEditText.getRootWindowInsets();
+        return insets.isVisible(WindowInsets.Type.ime());
+    }
+
+    public void showIme() {
+        mEditText.requestFocus();
+        InputMethodManager imm = getSystemService(InputMethodManager.class);
+        imm.showSoftInput(mEditText, 0);
+    }
+
+    public void hideIme() {
+        InputMethodManager imm = getSystemService(InputMethodManager.class);
+        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+    }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7b2a07f..7a668a5 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -31,7 +31,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.UserManager;
@@ -55,7 +54,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -204,194 +202,6 @@
     }
 
     /**
-     * Test that multiple available rollbacks are properly persisted.
-     */
-    @Test
-    public void testAvailableRollbackPersistence() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-
-            Uninstall.packages(TestApp.A);
-            Install.single(TestApp.A1).commit();
-            Install.single(TestApp.A2).setEnableRollback().commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
-            Uninstall.packages(TestApp.B);
-            Install.single(TestApp.B1).commit();
-            Install.single(TestApp.B2).setEnableRollback().commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
-            // Both test apps should now be available for rollback.
-            RollbackInfo rollbackA = waitForAvailableRollback(TestApp.A);
-            assertThat(rollbackA).isNotNull();
-            assertThat(rollbackA).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1));
-
-            RollbackInfo rollbackB = waitForAvailableRollback(TestApp.B);
-            assertThat(rollbackB).isNotNull();
-            assertThat(rollbackB).packagesContainsExactly(
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Reload the persisted data.
-            rm.reloadPersistedData();
-
-            // The apps should still be available for rollback.
-            rollbackA = waitForAvailableRollback(TestApp.A);
-            assertThat(rollbackA).isNotNull();
-            assertThat(rollbackA).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1));
-
-            rollbackB = waitForAvailableRollback(TestApp.B);
-            assertThat(rollbackB).isNotNull();
-            assertThat(rollbackB).packagesContainsExactly(
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Rollback of B should not rollback A
-            RollbackUtils.rollback(rollbackB.getRollbackId());
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Test that available multi-package rollbacks are properly persisted.
-     */
-    @Test
-    public void testAvailableMultiPackageRollbackPersistence() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-
-            Uninstall.packages(TestApp.A, TestApp.B);
-            Install.multi(TestApp.A1, TestApp.B1).commit();
-            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
-            // The app should now be available for rollback.
-            RollbackInfo availableA = waitForAvailableRollback(TestApp.A);
-            assertThat(availableA).isNotNull();
-            assertThat(availableA).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            RollbackInfo availableB = waitForAvailableRollback(TestApp.B);
-            assertThat(availableB).isNotNull();
-            assertThat(availableB).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Assert they're both the same rollback
-            assertThat(availableA).hasRollbackId(availableB.getRollbackId());
-
-            // Reload the persisted data.
-            rm.reloadPersistedData();
-
-            // The apps should still be available for rollback.
-            availableA = waitForAvailableRollback(TestApp.A);
-            assertThat(availableA).isNotNull();
-            assertThat(availableA).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            availableB = waitForAvailableRollback(TestApp.B);
-            assertThat(availableB).isNotNull();
-            assertThat(availableB).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Rollback of B should rollback A as well
-            RollbackUtils.rollback(availableB.getRollbackId());
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-
-            RollbackInfo committedA = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
-            assertThat(committedA).isNotNull();
-            assertThat(committedA).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            RollbackInfo committedB = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
-            assertThat(committedB).isNotNull();
-            assertThat(committedB).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Assert they're both the same rollback
-            assertThat(committedA).hasRollbackId(committedB.getRollbackId());
-            assertThat(committedA).hasRollbackId(availableA.getRollbackId());
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Test that recently committed rollback data is properly persisted.
-     */
-    @Test
-    public void testRecentlyCommittedRollbackPersistence() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-
-            Uninstall.packages(TestApp.A);
-            Install.single(TestApp.A1).commit();
-            Install.single(TestApp.A2).setEnableRollback().commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
-            // The app should now be available for rollback.
-            RollbackInfo available = waitForAvailableRollback(TestApp.A);
-            assertThat(available).isNotNull();
-
-            // Roll back the app.
-            TestApp cause = new TestApp("Foo", "com.android.tests.rollback.testapp.Foo",
-                    /*versionCode*/ 42, /*isApex*/ false);
-            RollbackUtils.rollback(available.getRollbackId(), cause);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
-            // Verify the recent rollback has been recorded.
-            RollbackInfo committed = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
-            assertThat(committed).isNotNull();
-            assertThat(committed).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1));
-            assertThat(committed).causePackagesContainsExactly(cause);
-
-            // Reload the persisted data.
-            rm.reloadPersistedData();
-
-            // Verify the recent rollback is still recorded.
-            committed = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
-            assertThat(committed).isNotNull();
-            assertThat(committed).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1));
-            assertThat(committed).causePackagesContainsExactly(cause);
-            assertThat(committed).hasRollbackId(available.getRollbackId());
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
      * Test the scheduling aspect of rollback expiration.
      */
     @Test
@@ -740,203 +550,6 @@
         }
     }
 
-    /**
-     * Test that the MANAGE_ROLLBACKS permission is required to call
-     * RollbackManager APIs.
-     */
-    @Test
-    public void testManageRollbacksPermission() throws Exception {
-        // We shouldn't be allowed to call any of the RollbackManager APIs
-        // without the MANAGE_ROLLBACKS permission.
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-
-        try {
-            rm.getAvailableRollbacks();
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-
-        try {
-            rm.getRecentlyCommittedRollbacks();
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-
-        try {
-            // TODO: What if the implementation checks arguments for non-null
-            // first? Then this test isn't valid.
-            rm.commitRollback(0, Collections.emptyList(), null);
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-
-        try {
-            rm.reloadPersistedData();
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-
-        try {
-            rm.expireRollbackForPackage(TestApp.A);
-            fail("expected SecurityException");
-        } catch (SecurityException e) {
-            // Expected.
-        }
-    }
-
-    /**
-     * Test that you cannot enable rollback for a package without the
-     * MANAGE_ROLLBACKS permission.
-     */
-    @Test
-    public void testEnableRollbackPermission() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES);
-
-            Uninstall.packages(TestApp.A);
-            Install.single(TestApp.A1).commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
-            Install.single(TestApp.A2).setEnableRollback().commit();
-
-            // We expect v2 of the app was installed, but rollback has not
-            // been enabled.
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-            assertThat(
-                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Test that you cannot enable rollback for a non-module package when
-     * holding the MANAGE_ROLLBACKS permission.
-     */
-    @Test
-    public void testNonModuleEnableRollback() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
-
-            Uninstall.packages(TestApp.A);
-            Install.single(TestApp.A1).commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
-            Install.single(TestApp.A2).setEnableRollback().commit();
-
-            // We expect v2 of the app was installed, but rollback has not
-            // been enabled because the test app is not a module.
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-            assertThat(
-                getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TestApp.A)).isNull();
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Test rollback of multi-package installs is implemented.
-     */
-    @Test
-    public void testMultiPackage() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-
-            // Prep installation of the test apps.
-            Uninstall.packages(TestApp.A, TestApp.B);
-            Install.multi(TestApp.A1, TestApp.B1).commit();
-            processUserData(TestApp.A);
-            processUserData(TestApp.B);
-            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-            processUserData(TestApp.A);
-            processUserData(TestApp.B);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
-            // TestApp.A should now be available for rollback.
-            RollbackInfo rollback = waitForAvailableRollback(TestApp.A);
-            assertThat(rollback).isNotNull();
-            assertThat(rollback).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            // Rollback the app. It should cause both test apps to be rolled
-            // back.
-            RollbackUtils.rollback(rollback.getRollbackId());
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
-
-            // We should see recent rollbacks listed for both A and B.
-            Thread.sleep(1000);
-            RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.A);
-
-            RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
-                    rm.getRecentlyCommittedRollbacks(), TestApp.B);
-            assertThat(rollback).packagesContainsExactly(
-                    Rollback.from(TestApp.A2).to(TestApp.A1),
-                    Rollback.from(TestApp.B2).to(TestApp.B1));
-
-            assertThat(rollbackA).hasRollbackId(rollbackB.getRollbackId());
-
-            processUserData(TestApp.A);
-            processUserData(TestApp.B);
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Test failure to enable rollback for multi-package installs.
-     * If any one of the packages fail to enable rollback, we shouldn't enable
-     * rollback for any package.
-     */
-    @Test
-    public void testMultiPackageEnableFail() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-            RollbackManager rm = RollbackUtils.getRollbackManager();
-
-            Uninstall.packages(TestApp.A, TestApp.B);
-            Install.single(TestApp.A1).commit();
-            // We should fail to enable rollback here because TestApp B is not
-            // already installed.
-            Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit();
-
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
-
-            assertThat(getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.A)).isNull();
-            assertThat(getUniqueRollbackInfoForPackage(
-                    rm.getAvailableRollbacks(), TestApp.B)).isNull();
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
     @Test
     @Ignore("b/120200473")
     /**
@@ -1160,109 +773,4 @@
             InstallUtils.dropShellPermissionIdentity();
         }
     }
-
-    /**
-     * Test we can't enable rollback for non-whitelisted app without
-     * TEST_MANAGE_ROLLBACKS permission
-     */
-    @Test
-    public void testNonRollbackWhitelistedApp() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
-
-            Uninstall.packages(TestApp.A);
-            Install.single(TestApp.A1).commit();
-            assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
-
-            Install.single(TestApp.A2).setEnableRollback().commit();
-            Thread.sleep(TimeUnit.SECONDS.toMillis(2));
-            assertThat(RollbackUtils.getAvailableRollback(TestApp.A)).isNull();
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    @Test
-    public void testRollbackDataPolicy() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
-
-            Uninstall.packages(TestApp.A, TestApp.B, TestApp.C);
-            Install.multi(TestApp.A1, TestApp.B1, TestApp.C1).commit();
-            // Write user data version = 1
-            InstallUtils.processUserData(TestApp.A);
-            InstallUtils.processUserData(TestApp.B);
-            InstallUtils.processUserData(TestApp.C);
-
-            Install a2 = Install.single(TestApp.A2)
-                    .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
-            Install b2 = Install.single(TestApp.B2)
-                    .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
-            // The rollback data policy of C2 is specified in the manifest
-            Install c2 = Install.single(TestApp.C2).setEnableRollback();
-            Install.multi(a2, b2, c2).setEnableRollback().commit();
-            // Write user data version = 2
-            InstallUtils.processUserData(TestApp.A);
-            InstallUtils.processUserData(TestApp.B);
-            InstallUtils.processUserData(TestApp.C);
-
-            RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
-            RollbackUtils.rollback(info.getRollbackId());
-            // Read user data version from userdata.txt
-            // A's user data version is -1 for user data is wiped.
-            // B's user data version is 1 as rollback committed.
-            // C's user data version is -1 for user data is wiped.
-            assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
-            assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
-            assertThat(InstallUtils.getUserDataVersion(TestApp.C)).isEqualTo(-1);
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Tests an app can be rolled back to the previous signing key.
-     *
-     * <p>The rollback capability in the signing lineage allows an app to be updated to an APK
-     * signed with a previous signing key in the lineage; however this often defeats the purpose
-     * of key rotation as a compromised key could then be used to roll an app back to the previous
-     * key. To avoid requiring the rollback capability to support app rollbacks the PackageManager
-     * allows an app to be rolled back to the previous signing key if the rollback install reason
-     * is set.
-     */
-    @Test
-    public void testRollbackAfterKeyRotation() throws Exception {
-        try {
-            InstallUtils.adoptShellPermissionIdentity(
-                    Manifest.permission.INSTALL_PACKAGES,
-                    Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
-                    Manifest.permission.MANAGE_ROLLBACKS);
-
-            // Uninstall TestApp.A
-            Uninstall.packages(TestApp.A);
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
-
-            // Install v1 of the app with the original signing key (without rollbacks enabled).
-            Install.single(TestApp.AOriginal1).commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-
-            // Upgrade from v1 to v2 with the rotated signing key, with rollbacks enabled.
-            Install.single(TestApp.ARotated2).setEnableRollback().commit();
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
-
-            // Roll back the app.
-            RollbackInfo available = waitForAvailableRollback(TestApp.A);
-            RollbackUtils.rollback(available.getRollbackId());
-            assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
-        } finally {
-            InstallUtils.dropShellPermissionIdentity();
-        }
-    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 642b19e..e874782 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -301,9 +301,9 @@
         InstallUtils.processUserData(TestApp.C);
 
         Install a2 = Install.single(TestApp.A2).setStaged()
-                .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
+                .setEnableRollback(PackageManager.ROLLBACK_DATA_POLICY_WIPE);
         Install b2 = Install.single(TestApp.B2).setStaged()
-                .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
+                .setEnableRollback(PackageManager.ROLLBACK_DATA_POLICY_RESTORE);
         // The rollback data policy of C2 is specified in the manifest
         Install c2 = Install.single(TestApp.C2).setStaged().setEnableRollback();
         Install.multi(a2, b2, c2).setEnableRollback().setStaged().commit();
diff --git a/tests/UpdatableSystemFontTest/Android.bp b/tests/UpdatableSystemFontTest/Android.bp
index dc090aa..c59a41e 100644
--- a/tests/UpdatableSystemFontTest/Android.bp
+++ b/tests/UpdatableSystemFontTest/Android.bp
@@ -37,10 +37,10 @@
         "vts",
     ],
     data: [
-        ":NotoColorEmoji.ttf",
         ":NotoSerif-Regular.ttf",
         ":NotoSerif-Bold.ttf",
         ":UpdatableSystemFontTestCertDer",
+        ":UpdatableSystemFontTest_NotoColorEmoji.ttf",
         ":UpdatableSystemFontTest_NotoColorEmoji.sig",
         ":UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
         ":UpdatableSystemFontTest_NotoColorEmojiV0.sig",
diff --git a/tests/UpdatableSystemFontTest/testdata/Android.bp b/tests/UpdatableSystemFontTest/testdata/Android.bp
index 5eba336..64b698d 100644
--- a/tests/UpdatableSystemFontTest/testdata/Android.bp
+++ b/tests/UpdatableSystemFontTest/testdata/Android.bp
@@ -22,9 +22,9 @@
 }
 
 // An existing module name is reused to avoid merge conflicts.
-// TODO: fix the font and module name.
+// TODO: fix the font file name.
 filegroup {
-    name: "NotoColorEmojiTtf",
+    name: "UpdatableSystemFontTest_NotoColorEmoji.ttf",
     srcs: ["NotoColorEmoji.ttf"],
 }
 
@@ -49,7 +49,7 @@
 
 genrule {
     name: "UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
-    srcs: [":NotoColorEmoji.ttf"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
     out: ["UpdatableSystemFontTest_NotoColorEmojiV0.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
@@ -60,7 +60,7 @@
 
 genrule {
     name: "UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
-    srcs: [":NotoColorEmoji.ttf"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
     out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
@@ -71,7 +71,7 @@
 
 genrule {
     name: "UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
-    srcs: [":NotoColorEmoji.ttf"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
     out: ["UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf"],
     tools: ["update_font_metadata"],
     cmd: "$(location update_font_metadata) " +
@@ -96,7 +96,7 @@
 genrule {
     name: "UpdatableSystemFontTest_NotoColorEmoji.sig",
     defaults: ["updatable_system_font_sig_gen_default"],
-    srcs: [":NotoColorEmoji.ttf"],
+    srcs: [":UpdatableSystemFontTest_NotoColorEmoji.ttf"],
     out: ["UpdatableSystemFontTest_NotoColorEmoji.sig"],
 }
 
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index ea886db..0bbde62 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@
 
 static ApiVersion sDevelopmentSdkLevel = 10000;
 static const auto sDevelopmentSdkCodeNames =
-    std::unordered_set<StringPiece>({"Q", "R", "S", "Tiramisu"});
+    std::unordered_set<StringPiece>({"Q", "R", "S", "Sv2", "Tiramisu"});
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
     {0x021c, 1},
diff --git a/tools/codegen/OWNERS b/tools/codegen/OWNERS
index da723b3..c9bd260 100644
--- a/tools/codegen/OWNERS
+++ b/tools/codegen/OWNERS
@@ -1 +1 @@
-eugenesusla@google.com
\ No newline at end of file
+chiuwinson@google.com
diff --git a/tools/codegen/src/com/android/codegen/ImportsProvider.kt b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
index 27dd958..46df273 100644
--- a/tools/codegen/src/com/android/codegen/ImportsProvider.kt
+++ b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
@@ -53,10 +53,25 @@
      * Optionally shortens a class reference if there's a corresponding import present
      */
     fun classRef(fullName: String): String {
-
         val pkg = fullName.substringBeforeLast(".")
         val simpleName = fullName.substringAfterLast(".")
-        if (fileAst.imports.any { imprt ->
+        val imports = fileAst.imports
+
+        // If an import of the same class name is available,
+        // use it instead of the internal Android package variants.
+        if (fullName.startsWith("com.android.internal.util.")
+            && imports.any {
+                it.nameAsString.endsWith(fullName.removePrefix("com.android.internal.util."))
+            }
+        ) {
+            return fullName.removePrefix("com.android.internal.util.")
+        } else if (fullName.startsWith("android.annotation")
+            && imports.any { it.nameAsString.endsWith(simpleName) }
+        ) {
+            return simpleName
+        }
+
+        if (imports.any { imprt ->
                     imprt.nameAsString == fullName
                             || (imprt.isAsterisk && imprt.nameAsString == pkg)
                 }) {
@@ -89,4 +104,4 @@
 /** @see classRef */
 inline fun <reified T : Any> ImportsProvider.classRef(): String {
     return classRef(T::class.java.name)
-}
\ No newline at end of file
+}
diff --git a/tools/lint/Android.bp b/tools/lint/Android.bp
index dcbc32b..17547ef 100644
--- a/tools/lint/Android.bp
+++ b/tools/lint/Android.bp
@@ -31,16 +31,16 @@
     ],
 }
 
-// TODO: (b/162368644) Implement these (working in gradle) Kotlin Tests to run on Soong
-//java_test_host {
-//    name: "AndroidFrameworkLintCheckerTest",
-//    srcs: [
-//     "checks/src/test/java/**/*.kt",
-//     "checks/src/main/java/**/*.kt",
-//    ],
-//    plugins: ["auto_service_plugin"],
-//    static_libs: [
-//        "auto_service_annotations",
-//        "lint_api",
-//    ],
-//}
+java_test_host {
+    name: "AndroidFrameworkLintCheckerTest",
+    srcs: ["checks/src/test/java/**/*.kt"],
+    static_libs: [
+        "AndroidFrameworkLintChecker",
+        "junit",
+        "lint",
+        "lint_tests",
+    ],
+    test_options: {
+        unit_test: true,
+    },
+}
diff --git a/tools/lint/README.md b/tools/lint/README.md
new file mode 100644
index 0000000..d661bc4
--- /dev/null
+++ b/tools/lint/README.md
@@ -0,0 +1,51 @@
+# Android Framework Lint Checker
+
+Custom lint checks written here are going to be executed for modules that opt in to those (e.g. any
+`services.XXX` module) and results will be automatically reported on CLs on gerrit.
+
+## How to add new lint checks
+
+1. Write your detector with its issues and put it into
+   `checks/src/main/java/com/google/android/lint`.
+2. Add your detector's issues into `AndroidFrameworkIssueRegistry`'s `issues` field.
+3. Write unit tests for your detector in one file and put it into
+   `checks/test/java/com/google/android/lint`.
+4. Done! Your lint checks should be applied in lint report builds for modules that include
+   `AndroidFrameworkLintChecker`.
+
+## How to run lint against your module
+
+1. Add the following `lint` attribute to the module definition, e.g. `services.autofill`:
+```
+java_library_static {
+    name: "services.autofill",
+    ...
+    lint: {
+        extra_check_modules: ["AndroidFrameworkLintChecker"],
+    },
+}
+```
+2. Run the following command to verify that the report is being correctly built:
+```
+m out/soong/.intermediates/frameworks/base/services/autofill/services.autofill/android_common/lint/lint-report.html
+```
+   (Lint report can be found in the same path, i.e. `out/../lint-report.html`)
+3. Now lint issues should appear on gerrit!
+
+**Notes:**
+
+- Lint report will not be produced if you just build the module, i.e. `m services.autofill` will not
+  build the lint report.
+- If you want to build lint reports for more than 1 module and they depend on a common module, e.g.
+  `platform_service_defaults`, you can add the `lint` property to that common module instead of
+  adding it in every module.
+
+## Documentation
+
+- [go/android-security-lint-checks](http://go/android-security-lint-checks) - presentation about
+  this module
+- [Android Lint Docs](http://googlesamples.github.io/android-custom-lint-rules/)
+- [Android Lint source files](https://source.corp.google.com/studio-main/tools/base/lint/libs/lint-api/src/main/java/com/android/tools/lint/)
+- [PSI source files](https://github.com/JetBrains/intellij-community/tree/master/java/java-psi-api/src/com/intellij/psi)
+- [UAST source files](https://upsource.jetbrains.com/idea-ce/structure/idea-ce-7b9b8cc138bbd90aec26433f82cd2c6838694003/uast/uast-common/src/org/jetbrains/uast)
+- [IntelliJ plugin for viewing PSI tree of files](https://plugins.jetbrains.com/plugin/227-psiviewer)
diff --git a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.kt b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.kt
deleted file mode 100644
index a41d65d..0000000
--- a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenDetector.kt
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.lint
-
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_NESTED_CLEAR_IDENTITY_CALLS
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_NON_FINAL_TOKEN
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_UNUSED_TOKEN
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageClearIdentityCallNotFollowedByTryFinally
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNestedClearIdentityCallsPrimary
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNestedClearIdentityCallsSecondary
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageNonFinalToken
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageRestoreIdentityCallNotInFinallyBlock
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageUnusedToken
-import com.android.lint.CallingIdentityTokenIssueRegistry.Companion.getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity
-import com.android.tools.lint.client.api.UElementHandler
-import com.android.tools.lint.detector.api.Context
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.Location
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.intellij.psi.PsiMethod
-import com.intellij.psi.search.PsiSearchScopeUtil
-import com.intellij.psi.search.SearchScope
-import org.jetbrains.uast.UBlockExpression
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.UDeclarationsExpression
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.ULocalVariable
-import org.jetbrains.uast.UQualifiedReferenceExpression
-import org.jetbrains.uast.USimpleNameReferenceExpression
-import org.jetbrains.uast.UTryExpression
-import org.jetbrains.uast.getParentOfType
-
-/**
- * Lint Detector that finds issues with improper usages of the token returned by
- * Binder.clearCallingIdentity()
- */
-@Suppress("UnstableApiUsage")
-class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
-    private companion object {
-        const val CLASS_BINDER = "android.os.Binder"
-        const val CLASS_USER_HANDLE = "android.os.UserHandle"
-
-        @JvmField
-        val callerAwareMethods = listOf(
-                Method.BINDER_GET_CALLING_PID,
-                Method.BINDER_GET_CALLING_UID,
-                Method.BINDER_GET_CALLING_UID_OR_THROW,
-                Method.BINDER_GET_CALLING_USER_HANDLE,
-                Method.USER_HANDLE_GET_CALLING_APP_ID,
-                Method.USER_HANDLE_GET_CALLING_USER_ID
-        )
-    }
-
-    /** Map of <Token variable name, Token object> */
-    private val tokensMap = mutableMapOf<String, Token>()
-
-    override fun getApplicableUastTypes(): List<Class<out UElement?>> =
-            listOf(ULocalVariable::class.java, UQualifiedReferenceExpression::class.java)
-
-    override fun createUastHandler(context: JavaContext): UElementHandler =
-            TokenUastHandler(context)
-
-    /** File analysis starts with a clear map */
-    override fun beforeCheckFile(context: Context) {
-        tokensMap.clear()
-    }
-
-    /**
-     * - If tokensMap has tokens after checking the file -> reports all locations as unused token
-     * issue incidents
-     * - File analysis ends with a clear map
-     */
-    override fun afterCheckFile(context: Context) {
-        for (token in tokensMap.values) {
-            context.report(
-                    ISSUE_UNUSED_TOKEN,
-                    token.location,
-                    getIncidentMessageUnusedToken(token.variableName)
-            )
-        }
-        tokensMap.clear()
-    }
-
-    /** UAST handler that analyses elements and reports incidents */
-    private inner class TokenUastHandler(val context: JavaContext) : UElementHandler() {
-        /**
-         * For every variable initialization with Binder.clearCallingIdentity():
-         * - Checks for non-final token issue
-         * - Checks for unused token issue within different scopes
-         * - Checks for nested calls of clearCallingIdentity() issue
-         * - Checks for clearCallingIdentity() not followed by try-finally issue
-         * - Stores token variable name, scope in the file, location and finally block in tokensMap
-         */
-        override fun visitLocalVariable(node: ULocalVariable) {
-            val rhsExpression = node.uastInitializer as? UQualifiedReferenceExpression ?: return
-            if (!isMethodCall(rhsExpression, Method.BINDER_CLEAR_CALLING_IDENTITY)) return
-            val location = context.getLocation(node as UElement)
-            val variableName = node.getName()
-            if (!node.isFinal) {
-                context.report(
-                        ISSUE_NON_FINAL_TOKEN,
-                        location,
-                        getIncidentMessageNonFinalToken(variableName)
-                )
-            }
-            // If there exists an unused variable with the same name in the map, we can imply that
-            // we left the scope of the previous declaration, so we need to report the unused token
-            val oldToken = tokensMap[variableName]
-            if (oldToken != null) {
-                context.report(
-                        ISSUE_UNUSED_TOKEN,
-                        oldToken.location,
-                        getIncidentMessageUnusedToken(oldToken.variableName)
-                )
-            }
-            // If there exists a token in the same scope as the current new token, it means that
-            // clearCallingIdentity() has been called at least twice without immediate restoration
-            // of identity, so we need to report the nested call of clearCallingIdentity()
-            val firstCallToken = findFirstTokenInScope(node)
-            if (firstCallToken != null) {
-                context.report(
-                        ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
-                        createNestedLocation(firstCallToken, location),
-                        getIncidentMessageNestedClearIdentityCallsPrimary(
-                                firstCallToken.variableName,
-                                variableName
-                        )
-                )
-            }
-            // If the next statement in the tree is not a try-finally statement, we need to report
-            // the "clearCallingIdentity() is not followed by try-finally" issue
-            val finallyClause = (getNextStatementOfLocalVariable(node) as? UTryExpression)
-                    ?.finallyClause
-            if (finallyClause == null) {
-                context.report(
-                        ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
-                        location,
-                        getIncidentMessageClearIdentityCallNotFollowedByTryFinally(variableName)
-                )
-            }
-            tokensMap[variableName] = Token(
-                    variableName,
-                    node.sourcePsi?.getUseScope(),
-                    location,
-                    finallyClause
-            )
-        }
-
-        /**
-         * For every class.method():
-         * - Checks use of caller-aware methods issue
-         * For every call of Binder.restoreCallingIdentity(token):
-         * - Checks for restoreCallingIdentity() not in the finally block issue
-         * - Removes token from tokensMap if token is within the scope of the method
-         */
-        override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) {
-            val token = findFirstTokenInScope(node)
-            if (isCallerAwareMethod(node) && token != null) {
-                context.report(
-                        ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
-                        context.getLocation(node),
-                        getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
-                                token.variableName,
-                                node.asRenderString()
-                        )
-                )
-                return
-            }
-            if (!isMethodCall(node, Method.BINDER_RESTORE_CALLING_IDENTITY)) return
-            val selector = node.selector as UCallExpression
-            val arg = selector.valueArguments[0] as? USimpleNameReferenceExpression ?: return
-            val variableName = arg.identifier
-            val originalScope = tokensMap[variableName]?.scope ?: return
-            val psi = arg.sourcePsi ?: return
-            // Checks if Binder.restoreCallingIdentity(token) is called within the scope of the
-            // token declaration. If not within the scope, no action is needed because the token is
-            // irrelevant i.e. not in the same scope or was not declared with clearCallingIdentity()
-            if (!PsiSearchScopeUtil.isInScope(originalScope, psi)) return
-            // We do not report "restore identity call not in finally" issue when there is no
-            // finally block because that case is already handled by "clear identity call not
-            // followed by try-finally" issue
-            if (tokensMap[variableName]?.finallyBlock != null &&
-                    node.uastParent != tokensMap[variableName]?.finallyBlock) {
-                context.report(
-                        ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
-                        context.getLocation(node),
-                        getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName)
-                )
-            }
-            tokensMap.remove(variableName)
-        }
-
-        private fun isCallerAwareMethod(expression: UQualifiedReferenceExpression): Boolean =
-                callerAwareMethods.any { method -> isMethodCall(expression, method) }
-
-        private fun isMethodCall(
-            expression: UQualifiedReferenceExpression,
-            method: Method
-        ): Boolean {
-            val psiMethod = expression.resolve() as? PsiMethod ?: return false
-            return psiMethod.getName() == method.methodName &&
-                    context.evaluator.methodMatches(
-                            psiMethod,
-                            method.className,
-                            /* allowInherit */ true,
-                            *method.args
-                    )
-        }
-
-        /**
-         * ULocalVariable in the file tree:
-         *
-         * UBlockExpression
-         *     UDeclarationsExpression
-         *         ULocalVariable
-         *         ULocalVariable
-         *     UTryStatement
-         *     etc.
-         *
-         * To get the next statement of ULocalVariable:
-         * - If there exists a next sibling in UDeclarationsExpression, return the sibling
-         * - If there exists a next sibling of UDeclarationsExpression in UBlockExpression, return
-         *   the sibling
-         * - Otherwise, return null
-         *
-         * Example 1 - the next sibling is in UDeclarationsExpression:
-         * Code:
-         * {
-         *     int num1 = 0, num2 = methodThatThrowsException();
-         * }
-         * Returns: num2 = methodThatThrowsException()
-         *
-         * Example 2 - the next sibling is in UBlockExpression:
-         * Code:
-         * {
-         *     int num1 = 0;
-         *     methodThatThrowsException();
-         * }
-         * Returns: methodThatThrowsException()
-         *
-         * Example 3 - no next sibling;
-         * Code:
-         * {
-         *     int num1 = 0;
-         * }
-         * Returns: null
-         */
-        private fun getNextStatementOfLocalVariable(node: ULocalVariable): UElement? {
-            val declarationsExpression = node.uastParent as? UDeclarationsExpression ?: return null
-            val declarations = declarationsExpression.declarations
-            val indexInDeclarations = declarations.indexOf(node)
-            if (indexInDeclarations != -1 && declarations.size > indexInDeclarations + 1) {
-                return declarations[indexInDeclarations + 1]
-            }
-            val enclosingBlock = node
-                    .getParentOfType<UBlockExpression>(strict = true) ?: return null
-            val expressions = enclosingBlock.expressions
-            val indexInBlock = expressions.indexOf(declarationsExpression as UElement)
-            return if (indexInBlock == -1) null else expressions.getOrNull(indexInBlock + 1)
-        }
-    }
-
-    private fun findFirstTokenInScope(node: UElement): Token? {
-        val psi = node.sourcePsi ?: return null
-        for (token in tokensMap.values) {
-            if (token.scope != null && PsiSearchScopeUtil.isInScope(token.scope, psi)) {
-                return token
-            }
-        }
-        return null
-    }
-
-    /**
-     * Creates a new instance of the primary location with the secondary location
-     *
-     * Here, secondary location is the helper location that shows where the issue originated
-     *
-     * The detector reports locations as objects, so when we add a secondary location to a location
-     * that has multiple issues, the secondary location gets displayed every time a location is
-     * referenced.
-     *
-     * Example:
-     * 1: final long token1 = Binder.clearCallingIdentity();
-     * 2: long token2 = Binder.clearCallingIdentity();
-     * 3: Binder.restoreCallingIdentity(token1);
-     * 4: Binder.restoreCallingIdentity(token2);
-     *
-     * Explanation:
-     * token2 has 2 issues: NonFinal and NestedCalls
-     *
-     *     Lint report without cloning                        Lint report with cloning
-     * line 2: [NonFinalIssue]                            line 2: [NonFinalIssue]
-     *     line 1: [NestedCallsIssue]
-     * line 2: [NestedCallsIssue]                            line 2: [NestedCallsIssue]
-     *     line 1: [NestedCallsIssue]                           line 1: [NestedCallsIssue]
-     */
-    private fun createNestedLocation(
-        firstCallToken: Token,
-        secondCallTokenLocation: Location
-    ): Location {
-        return cloneLocation(secondCallTokenLocation)
-                .withSecondary(
-                        cloneLocation(firstCallToken.location),
-                        getIncidentMessageNestedClearIdentityCallsSecondary(
-                                firstCallToken.variableName
-                        )
-                )
-    }
-
-    private fun cloneLocation(location: Location): Location {
-        // smart cast of location.start to 'Position' is impossible, because 'location.start' is a
-        // public API property declared in different module
-        val locationStart = location.start
-        return if (locationStart == null) {
-            Location.create(location.file)
-        } else {
-            Location.create(location.file, locationStart, location.end)
-        }
-    }
-
-    private enum class Method(
-        val className: String,
-        val methodName: String,
-        val args: Array<String>
-    ) {
-        BINDER_CLEAR_CALLING_IDENTITY(CLASS_BINDER, "clearCallingIdentity", emptyArray()),
-        BINDER_RESTORE_CALLING_IDENTITY(CLASS_BINDER, "restoreCallingIdentity", arrayOf("long")),
-        BINDER_GET_CALLING_PID(CLASS_BINDER, "getCallingPid", emptyArray()),
-        BINDER_GET_CALLING_UID(CLASS_BINDER, "getCallingUid", emptyArray()),
-        BINDER_GET_CALLING_UID_OR_THROW(CLASS_BINDER, "getCallingUidOrThrow", emptyArray()),
-        BINDER_GET_CALLING_USER_HANDLE(CLASS_BINDER, "getCallingUserHandle", emptyArray()),
-        USER_HANDLE_GET_CALLING_APP_ID(CLASS_USER_HANDLE, "getCallingAppId", emptyArray()),
-        USER_HANDLE_GET_CALLING_USER_ID(CLASS_USER_HANDLE, "getCallingUserId", emptyArray())
-    }
-
-    private data class Token(
-        val variableName: String,
-        val scope: SearchScope?,
-        val location: Location,
-        val finallyBlock: UElement?
-    )
-}
diff --git a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt b/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt
deleted file mode 100644
index 1bd63ea..0000000
--- a/tools/lint/checks/src/main/java/com/android/lint/CallingIdentityTokenIssueRegistry.kt
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.lint
-
-import com.android.tools.lint.client.api.IssueRegistry
-// TODO: uncomment when lint API in Soong becomes 30.0+
-// import com.android.tools.lint.client.api.Vendor
-import com.android.tools.lint.detector.api.CURRENT_API
-import com.android.tools.lint.detector.api.Category
-import com.android.tools.lint.detector.api.Implementation
-import com.android.tools.lint.detector.api.Issue
-import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.detector.api.Severity
-import com.google.auto.service.AutoService
-
-@AutoService(IssueRegistry::class)
-@Suppress("UnstableApiUsage")
-class CallingIdentityTokenIssueRegistry : IssueRegistry() {
-    override val issues = listOf(
-            ISSUE_UNUSED_TOKEN,
-            ISSUE_NON_FINAL_TOKEN,
-            ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
-            ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
-            ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
-            ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY
-    )
-
-    override val api: Int
-        get() = CURRENT_API
-
-    override val minApi: Int
-        get() = 8
-
-//    TODO: uncomment when lint API in Soong becomes 30.0+
-//    override val vendor: Vendor = Vendor(
-//            vendorName = "Android Open Source Project",
-//            feedbackUrl = "http://b/issues/new?component=315013",
-//            contact = "brufino@google.com"
-//    )
-
-    companion object {
-        /** Issue: unused token from Binder.clearCallingIdentity() */
-        @JvmField
-        val ISSUE_UNUSED_TOKEN: Issue = Issue.create(
-                id = "UnusedTokenOfOriginalCallingIdentity",
-                briefDescription = "Unused token of Binder.clearCallingIdentity()",
-                explanation = """
-                    You cleared the original calling identity with \
-                    `Binder.clearCallingIdentity()`, but have not used the returned token to \
-                    restore the identity.
-
-                    Call `Binder.restoreCallingIdentity(token)` in the `finally` block, at the end \
-                    of the method or when you need to restore the identity.
-
-                    `token` is the result of `Binder.clearCallingIdentity()`
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageUnusedToken(variableName: String) = "`$variableName` has not been " +
-                "used to restore the calling identity. Introduce a `try`-`finally` after the " +
-                "declaration and call `Binder.restoreCallingIdentity($variableName)` in " +
-                "`finally` or remove `$variableName`."
-
-        /** Issue: non-final token from Binder.clearCallingIdentity() */
-        @JvmField
-        val ISSUE_NON_FINAL_TOKEN: Issue = Issue.create(
-                id = "NonFinalTokenOfOriginalCallingIdentity",
-                briefDescription = "Non-final token of Binder.clearCallingIdentity()",
-                explanation = """
-                    You cleared the original calling identity with \
-                    `Binder.clearCallingIdentity()`, but have not made the returned token `final`.
-
-                    The token should be `final` in order to prevent it from being overwritten, \
-                    which can cause problems when restoring the identity with \
-                    `Binder.restoreCallingIdentity(token)`.
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageNonFinalToken(variableName: String) = "`$variableName` is a " +
-                "non-final token from `Binder.clearCallingIdentity()`. Add `final` keyword to " +
-                "`$variableName`."
-
-        /** Issue: nested calls of Binder.clearCallingIdentity() */
-        @JvmField
-        val ISSUE_NESTED_CLEAR_IDENTITY_CALLS: Issue = Issue.create(
-                id = "NestedClearCallingIdentityCalls",
-                briefDescription = "Nested calls of Binder.clearCallingIdentity()",
-                explanation = """
-                    You cleared the original calling identity with \
-                    `Binder.clearCallingIdentity()` twice without restoring identity with the \
-                    result of the first call.
-
-                    Make sure to restore the identity after each clear identity call.
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageNestedClearIdentityCallsPrimary(
-            firstCallVariableName: String,
-            secondCallVariableName: String
-        ): String = "The calling identity has already been cleared and returned into " +
-                "`$firstCallVariableName`. Move `$secondCallVariableName` declaration after " +
-                "restoring the calling identity with " +
-                "`Binder.restoreCallingIdentity($firstCallVariableName)`."
-
-        fun getIncidentMessageNestedClearIdentityCallsSecondary(
-            firstCallVariableName: String
-        ): String = "Location of the `$firstCallVariableName` declaration."
-
-        /** Issue: Binder.clearCallingIdentity() is not followed by `try-finally` statement */
-        @JvmField
-        val ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY: Issue = Issue.create(
-                id = "ClearIdentityCallNotFollowedByTryFinally",
-                briefDescription = "Binder.clearCallingIdentity() is not followed by try-finally " +
-                        "statement",
-                explanation = """
-                    You cleared the original calling identity with \
-                    `Binder.clearCallingIdentity()`, but the next statement is not a `try` \
-                    statement.
-
-                    Use the following pattern for running operations with your own identity:
-
-                    ```
-                    final long token = Binder.clearCallingIdentity();
-                    try {
-                        // Code using your own identity
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-                    ```
-
-                    Any calls/operations between `Binder.clearCallingIdentity()` and `try` \
-                    statement risk throwing an exception without doing a safe and unconditional \
-                    restore of the identity with `Binder.restoreCallingIdentity()` as an immediate \
-                    child of the `finally` block. If you do not follow the pattern, you may run \
-                    code with your identity that was originally intended to run with the calling \
-                    application's identity.
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageClearIdentityCallNotFollowedByTryFinally(
-            variableName: String
-        ): String = "You cleared the calling identity and returned the result into " +
-                "`$variableName`, but the next statement is not a `try`-`finally` statement. " +
-                "Define a `try`-`finally` block after `$variableName` declaration to ensure a " +
-                "safe restore of the calling identity by calling " +
-                "`Binder.restoreCallingIdentity($variableName)` and making it an immediate child " +
-                "of the `finally` block."
-
-        /** Issue: Binder.restoreCallingIdentity() is not in finally block */
-        @JvmField
-        val ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK: Issue = Issue.create(
-                id = "RestoreIdentityCallNotInFinallyBlock",
-                briefDescription = "Binder.restoreCallingIdentity() is not in finally block",
-                explanation = """
-                    You are restoring the original calling identity with \
-                    `Binder.restoreCallingIdentity()`, but the call is not an immediate child of \
-                    the `finally` block of the `try` statement.
-
-                    Use the following pattern for running operations with your own identity:
-
-                    ```
-                    final long token = Binder.clearCallingIdentity();
-                    try {
-                        // Code using your own identity
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-                    ```
-
-                    If you do not surround the code using your identity with the `try` statement \
-                    and call `Binder.restoreCallingIdentity()` as an immediate child of the \
-                    `finally` block, you may run code with your identity that was originally \
-                    intended to run with the calling application's identity.
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName: String): String =
-                "`Binder.restoreCallingIdentity($variableName)` is not an immediate child of the " +
-                        "`finally` block of the try statement after `$variableName` declaration. " +
-                        "Surround the call with `finally` block and call it unconditionally."
-
-        /** Issue: Use of caller-aware methods after Binder.clearCallingIdentity() */
-        @JvmField
-        val ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY: Issue = Issue.create(
-                id = "UseOfCallerAwareMethodsWithClearedIdentity",
-                briefDescription = "Use of caller-aware methods after " +
-                        "Binder.clearCallingIdentity()",
-                explanation = """
-                    You cleared the original calling identity with \
-                    `Binder.clearCallingIdentity()`, but used one of the methods below before \
-                    restoring the identity. These methods will use your own identity instead of \
-                    the caller's identity, so if this is expected replace them with methods that \
-                    explicitly query your own identity such as `Process.myUid()`, \
-                    `Process.myPid()` and `UserHandle.myUserId()`, otherwise move those methods \
-                    out of the `Binder.clearCallingIdentity()` / `Binder.restoreCallingIdentity()` \
-                    section.
-
-                    ```
-                    Binder.getCallingPid()
-                    Binder.getCallingUid()
-                    Binder.getCallingUidOrThrow()
-                    Binder.getCallingUserHandle()
-                    UserHandle.getCallingAppId()
-                    UserHandle.getCallingUserId()
-                    ```
-                    """,
-                category = Category.SECURITY,
-                priority = 6,
-                severity = Severity.WARNING,
-                implementation = Implementation(
-                        CallingIdentityTokenDetector::class.java,
-                        Scope.JAVA_FILE_SCOPE
-                )
-        )
-
-        fun getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
-            variableName: String,
-            methodName: String
-        ): String = "You cleared the original identity with `Binder.clearCallingIdentity()` " +
-                "and returned into `$variableName`, so `$methodName` will be using your own " +
-                "identity instead of the caller's. Either explicitly query your own identity or " +
-                "move it after restoring the identity with " +
-                "`Binder.restoreCallingIdentity($variableName)`."
-    }
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
new file mode 100644
index 0000000..900c214
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.auto.service.AutoService
+
+@AutoService(IssueRegistry::class)
+@Suppress("UnstableApiUsage")
+class AndroidFrameworkIssueRegistry : IssueRegistry() {
+    override val issues = listOf(
+            CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
+            CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
+            CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+            CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+            CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+            CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+            CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED
+    )
+
+    override val api: Int
+        get() = CURRENT_API
+
+    override val minApi: Int
+        get() = 8
+
+    override val vendor: Vendor = Vendor(
+            vendorName = "Android",
+            feedbackUrl = "http://b/issues/new?component=315013",
+            contact = "brufino@google.com"
+    )
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
new file mode 100644
index 0000000..c133226
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.search.PsiSearchScopeUtil
+import com.intellij.psi.search.SearchScope
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UDeclarationsExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.ULocalVariable
+import org.jetbrains.uast.USimpleNameReferenceExpression
+import org.jetbrains.uast.UTryExpression
+import org.jetbrains.uast.getParentOfType
+import org.jetbrains.uast.getQualifiedParentOrThis
+import org.jetbrains.uast.getUCallExpression
+
+/**
+ * Lint Detector that finds issues with improper usages of the token returned by
+ * Binder.clearCallingIdentity()
+ */
+@Suppress("UnstableApiUsage")
+class CallingIdentityTokenDetector : Detector(), SourceCodeScanner {
+    /** Map of <Token variable name, Token object> */
+    private val tokensMap = mutableMapOf<String, Token>()
+
+    override fun getApplicableUastTypes(): List<Class<out UElement?>> =
+            listOf(ULocalVariable::class.java, UCallExpression::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler =
+            TokenUastHandler(context)
+
+    /** File analysis starts with a clear map */
+    override fun beforeCheckFile(context: Context) {
+        tokensMap.clear()
+    }
+
+    /**
+     * - If tokensMap has tokens after checking the file -> reports all locations as unused token
+     * issue incidents
+     * - File analysis ends with a clear map
+     */
+    override fun afterCheckFile(context: Context) {
+        for (token in tokensMap.values) {
+            context.report(
+                    ISSUE_UNUSED_TOKEN,
+                    token.location,
+                    getIncidentMessageUnusedToken(token.variableName)
+            )
+        }
+        tokensMap.clear()
+    }
+
+    /** UAST handler that analyses elements and reports incidents */
+    private inner class TokenUastHandler(val context: JavaContext) : UElementHandler() {
+        /**
+         * For every variable initialization with Binder.clearCallingIdentity():
+         * - Checks for non-final token issue
+         * - Checks for unused token issue within different scopes
+         * - Checks for nested calls of clearCallingIdentity() issue
+         * - Checks for clearCallingIdentity() not followed by try-finally issue
+         * - Stores token variable name, scope in the file, location and finally block in tokensMap
+         */
+        override fun visitLocalVariable(node: ULocalVariable) {
+            val rhsExpression = node.uastInitializer?.getUCallExpression() ?: return
+            if (!isMethodCall(rhsExpression, Method.BINDER_CLEAR_CALLING_IDENTITY)) return
+            val location = context.getLocation(node as UElement)
+            val variableName = node.getName()
+            if (!node.isFinal) {
+                context.report(
+                        ISSUE_NON_FINAL_TOKEN,
+                        location,
+                        getIncidentMessageNonFinalToken(variableName)
+                )
+            }
+            // If there exists an unused variable with the same name in the map, we can imply that
+            // we left the scope of the previous declaration, so we need to report the unused token
+            val oldToken = tokensMap[variableName]
+            if (oldToken != null) {
+                context.report(
+                        ISSUE_UNUSED_TOKEN,
+                        oldToken.location,
+                        getIncidentMessageUnusedToken(oldToken.variableName)
+                )
+            }
+            // If there exists a token in the same scope as the current new token, it means that
+            // clearCallingIdentity() has been called at least twice without immediate restoration
+            // of identity, so we need to report the nested call of clearCallingIdentity()
+            val firstCallToken = findFirstTokenInScope(node)
+            if (firstCallToken != null) {
+                context.report(
+                        ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+                        createNestedLocation(firstCallToken, location),
+                        getIncidentMessageNestedClearIdentityCallsPrimary(
+                                firstCallToken.variableName,
+                                variableName
+                        )
+                )
+            }
+            // If the next statement in the tree is not a try-finally statement, we need to report
+            // the "clearCallingIdentity() is not followed by try-finally" issue
+            val finallyClause = (getNextStatementOfLocalVariable(node) as? UTryExpression)
+                    ?.finallyClause
+            if (finallyClause == null) {
+                context.report(
+                        ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+                        location,
+                        getIncidentMessageClearIdentityCallNotFollowedByTryFinally(variableName)
+                )
+            }
+            tokensMap[variableName] = Token(
+                    variableName,
+                    node.sourcePsi?.getUseScope(),
+                    location,
+                    finallyClause
+            )
+        }
+
+        /**
+         * For every method():
+         * - Checks use of caller-aware methods issue
+         * For every call of Binder.restoreCallingIdentity(token):
+         * - Checks for restoreCallingIdentity() not in the finally block issue
+         * - Removes token from tokensMap if token is within the scope of the method
+         */
+        override fun visitCallExpression(node: UCallExpression) {
+            val token = findFirstTokenInScope(node)
+            if (isCallerAwareMethod(node) && token != null) {
+                context.report(
+                        ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+                        context.getLocation(node),
+                        getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
+                                token.variableName,
+                                node.asRenderString()
+                        )
+                )
+                return
+            }
+            if (!isMethodCall(node, Method.BINDER_RESTORE_CALLING_IDENTITY)) return
+            val arg = node.valueArguments[0] as? USimpleNameReferenceExpression ?: return
+            val variableName = arg.identifier
+            val originalScope = tokensMap[variableName]?.scope ?: return
+            val psi = arg.sourcePsi ?: return
+            // Checks if Binder.restoreCallingIdentity(token) is called within the scope of the
+            // token declaration. If not within the scope, no action is needed because the token is
+            // irrelevant i.e. not in the same scope or was not declared with clearCallingIdentity()
+            if (!PsiSearchScopeUtil.isInScope(originalScope, psi)) return
+            // - We do not report "restore identity call not in finally" issue when there is no
+            // finally block because that case is already handled by "clear identity call not
+            // followed by try-finally" issue
+            // - UCallExpression can be a child of UQualifiedReferenceExpression, i.e.
+            // receiver.selector, so to get the call's immediate parent we need to get the topmost
+            // parent qualified reference expression and access its parent
+            if (tokensMap[variableName]?.finallyBlock != null &&
+                    node.getQualifiedParentOrThis().uastParent !=
+                        tokensMap[variableName]?.finallyBlock) {
+                context.report(
+                        ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+                        context.getLocation(node),
+                        getIncidentMessageRestoreIdentityCallNotInFinallyBlock(variableName)
+                )
+            }
+            tokensMap.remove(variableName)
+        }
+
+        private fun isCallerAwareMethod(expression: UCallExpression): Boolean =
+                callerAwareMethods.any { method -> isMethodCall(expression, method) }
+
+        private fun isMethodCall(
+            expression: UCallExpression,
+            method: Method
+        ): Boolean {
+            val psiMethod = expression.resolve() ?: return false
+            return psiMethod.getName() == method.methodName &&
+                    context.evaluator.methodMatches(
+                            psiMethod,
+                            method.className,
+                            /* allowInherit */ true,
+                            *method.args
+                    )
+        }
+
+        /**
+         * ULocalVariable in the file tree:
+         *
+         * UBlockExpression
+         *     UDeclarationsExpression
+         *         ULocalVariable
+         *         ULocalVariable
+         *     UTryStatement
+         *     etc.
+         *
+         * To get the next statement of ULocalVariable:
+         * - If there exists a next sibling in UDeclarationsExpression, return the sibling
+         * - If there exists a next sibling of UDeclarationsExpression in UBlockExpression, return
+         *   the sibling
+         * - Otherwise, return null
+         *
+         * Example 1 - the next sibling is in UDeclarationsExpression:
+         * Code:
+         * {
+         *     int num1 = 0, num2 = methodThatThrowsException();
+         * }
+         * Returns: num2 = methodThatThrowsException()
+         *
+         * Example 2 - the next sibling is in UBlockExpression:
+         * Code:
+         * {
+         *     int num1 = 0;
+         *     methodThatThrowsException();
+         * }
+         * Returns: methodThatThrowsException()
+         *
+         * Example 3 - no next sibling;
+         * Code:
+         * {
+         *     int num1 = 0;
+         * }
+         * Returns: null
+         */
+        private fun getNextStatementOfLocalVariable(node: ULocalVariable): UElement? {
+            val declarationsExpression = node.uastParent as? UDeclarationsExpression ?: return null
+            val declarations = declarationsExpression.declarations
+            val indexInDeclarations = declarations.indexOf(node)
+            if (indexInDeclarations != -1 && declarations.size > indexInDeclarations + 1) {
+                return declarations[indexInDeclarations + 1]
+            }
+            val enclosingBlock = node
+                    .getParentOfType<UBlockExpression>(strict = true) ?: return null
+            val expressions = enclosingBlock.expressions
+            val indexInBlock = expressions.indexOf(declarationsExpression as UElement)
+            return if (indexInBlock == -1) null else expressions.getOrNull(indexInBlock + 1)
+        }
+    }
+
+    private fun findFirstTokenInScope(node: UElement): Token? {
+        val psi = node.sourcePsi ?: return null
+        for (token in tokensMap.values) {
+            if (token.scope != null && PsiSearchScopeUtil.isInScope(token.scope, psi)) {
+                return token
+            }
+        }
+        return null
+    }
+
+    /**
+     * Creates a new instance of the primary location with the secondary location
+     *
+     * Here, secondary location is the helper location that shows where the issue originated
+     *
+     * The detector reports locations as objects, so when we add a secondary location to a location
+     * that has multiple issues, the secondary location gets displayed every time a location is
+     * referenced.
+     *
+     * Example:
+     * 1: final long token1 = Binder.clearCallingIdentity();
+     * 2: long token2 = Binder.clearCallingIdentity();
+     * 3: Binder.restoreCallingIdentity(token1);
+     * 4: Binder.restoreCallingIdentity(token2);
+     *
+     * Explanation:
+     * token2 has 2 issues: NonFinal and NestedCalls
+     *
+     *     Lint report without cloning                        Lint report with cloning
+     * line 2: [NonFinalIssue]                            line 2: [NonFinalIssue]
+     *     line 1: [NestedCallsIssue]
+     * line 2: [NestedCallsIssue]                            line 2: [NestedCallsIssue]
+     *     line 1: [NestedCallsIssue]                           line 1: [NestedCallsIssue]
+     */
+    private fun createNestedLocation(
+        firstCallToken: Token,
+        secondCallTokenLocation: Location
+    ): Location {
+        return cloneLocation(secondCallTokenLocation)
+                .withSecondary(
+                        cloneLocation(firstCallToken.location),
+                        getIncidentMessageNestedClearIdentityCallsSecondary(
+                                firstCallToken.variableName
+                        )
+                )
+    }
+
+    private fun cloneLocation(location: Location): Location {
+        // smart cast of location.start to 'Position' is impossible, because 'location.start' is a
+        // public API property declared in different module
+        val locationStart = location.start
+        return if (locationStart == null) {
+            Location.create(location.file)
+        } else {
+            Location.create(location.file, locationStart, location.end)
+        }
+    }
+
+    private enum class Method(
+        val className: String,
+        val methodName: String,
+        val args: Array<String>
+    ) {
+        BINDER_CLEAR_CALLING_IDENTITY(CLASS_BINDER, "clearCallingIdentity", emptyArray()),
+        BINDER_RESTORE_CALLING_IDENTITY(CLASS_BINDER, "restoreCallingIdentity", arrayOf("long")),
+        BINDER_GET_CALLING_PID(CLASS_BINDER, "getCallingPid", emptyArray()),
+        BINDER_GET_CALLING_UID(CLASS_BINDER, "getCallingUid", emptyArray()),
+        BINDER_GET_CALLING_UID_OR_THROW(CLASS_BINDER, "getCallingUidOrThrow", emptyArray()),
+        BINDER_GET_CALLING_USER_HANDLE(CLASS_BINDER, "getCallingUserHandle", emptyArray()),
+        USER_HANDLE_GET_CALLING_APP_ID(CLASS_USER_HANDLE, "getCallingAppId", emptyArray()),
+        USER_HANDLE_GET_CALLING_USER_ID(CLASS_USER_HANDLE, "getCallingUserId", emptyArray())
+    }
+
+    private data class Token(
+        val variableName: String,
+        val scope: SearchScope?,
+        val location: Location,
+        val finallyBlock: UElement?
+    )
+
+    companion object {
+        const val CLASS_BINDER = "android.os.Binder"
+        const val CLASS_USER_HANDLE = "android.os.UserHandle"
+
+        private val callerAwareMethods = listOf(
+                Method.BINDER_GET_CALLING_PID,
+                Method.BINDER_GET_CALLING_UID,
+                Method.BINDER_GET_CALLING_UID_OR_THROW,
+                Method.BINDER_GET_CALLING_USER_HANDLE,
+                Method.USER_HANDLE_GET_CALLING_APP_ID,
+                Method.USER_HANDLE_GET_CALLING_USER_ID
+        )
+
+        /** Issue: unused token from Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_UNUSED_TOKEN: Issue = Issue.create(
+                id = "UnusedTokenOfOriginalCallingIdentity",
+                briefDescription = "Unused token of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but have not used the returned token to \
+                    restore the identity.
+
+                    Call `Binder.restoreCallingIdentity(token)` in the `finally` block, at the end \
+                    of the method or when you need to restore the identity.
+
+                    `token` is the result of `Binder.clearCallingIdentity()`
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageUnusedToken(variableName: String) = "`$variableName` has " +
+                "not been used to restore the calling identity. Introduce a `try`-`finally` " +
+                "after the declaration and call `Binder.restoreCallingIdentity($variableName)` " +
+                "in `finally` or remove `$variableName`."
+
+        /** Issue: non-final token from Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_NON_FINAL_TOKEN: Issue = Issue.create(
+                id = "NonFinalTokenOfOriginalCallingIdentity",
+                briefDescription = "Non-final token of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but have not made the returned token `final`.
+
+                    The token should be `final` in order to prevent it from being overwritten, \
+                    which can cause problems when restoring the identity with \
+                    `Binder.restoreCallingIdentity(token)`.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageNonFinalToken(variableName: String) = "`$variableName` is " +
+                "a non-final token from `Binder.clearCallingIdentity()`. Add `final` keyword to " +
+                "`$variableName`."
+
+        /** Issue: nested calls of Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_NESTED_CLEAR_IDENTITY_CALLS: Issue = Issue.create(
+                id = "NestedClearCallingIdentityCalls",
+                briefDescription = "Nested calls of Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()` twice without restoring identity with the \
+                    result of the first call.
+
+                    Make sure to restore the identity after each clear identity call.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageNestedClearIdentityCallsPrimary(
+            firstCallVariableName: String,
+            secondCallVariableName: String
+        ): String = "The calling identity has already been cleared and returned into " +
+                "`$firstCallVariableName`. Move `$secondCallVariableName` declaration after " +
+                "restoring the calling identity with " +
+                "`Binder.restoreCallingIdentity($firstCallVariableName)`."
+
+        private fun getIncidentMessageNestedClearIdentityCallsSecondary(
+            firstCallVariableName: String
+        ): String = "Location of the `$firstCallVariableName` declaration."
+
+        /** Issue: Binder.clearCallingIdentity() is not followed by `try-finally` statement */
+        @JvmField
+        val ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY: Issue = Issue.create(
+                id = "ClearIdentityCallNotFollowedByTryFinally",
+                briefDescription = "Binder.clearCallingIdentity() is not followed by try-finally " +
+                        "statement",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but the next statement is not a `try` \
+                    statement.
+
+                    Use the following pattern for running operations with your own identity:
+
+                    ```
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        // Code using your own identity
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    ```
+
+                    Any calls/operations between `Binder.clearCallingIdentity()` and `try` \
+                    statement risk throwing an exception without doing a safe and unconditional \
+                    restore of the identity with `Binder.restoreCallingIdentity()` as an immediate \
+                    child of the `finally` block. If you do not follow the pattern, you may run \
+                    code with your identity that was originally intended to run with the calling \
+                    application's identity.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageClearIdentityCallNotFollowedByTryFinally(
+            variableName: String
+        ): String = "You cleared the calling identity and returned the result into " +
+                "`$variableName`, but the next statement is not a `try`-`finally` statement. " +
+                "Define a `try`-`finally` block after `$variableName` declaration to ensure a " +
+                "safe restore of the calling identity by calling " +
+                "`Binder.restoreCallingIdentity($variableName)` and making it an immediate child " +
+                "of the `finally` block."
+
+        /** Issue: Binder.restoreCallingIdentity() is not in finally block */
+        @JvmField
+        val ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK: Issue = Issue.create(
+                id = "RestoreIdentityCallNotInFinallyBlock",
+                briefDescription = "Binder.restoreCallingIdentity() is not in finally block",
+                explanation = """
+                    You are restoring the original calling identity with \
+                    `Binder.restoreCallingIdentity()`, but the call is not an immediate child of \
+                    the `finally` block of the `try` statement.
+
+                    Use the following pattern for running operations with your own identity:
+
+                    ```
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        // Code using your own identity
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    ```
+
+                    If you do not surround the code using your identity with the `try` statement \
+                    and call `Binder.restoreCallingIdentity()` as an immediate child of the \
+                    `finally` block, you may run code with your identity that was originally \
+                    intended to run with the calling application's identity.
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageRestoreIdentityCallNotInFinallyBlock(
+            variableName: String
+        ): String = "`Binder.restoreCallingIdentity($variableName)` is not an immediate child of " +
+                "the `finally` block of the try statement after `$variableName` declaration. " +
+                        "Surround the call with `finally` block and call it unconditionally."
+
+        /** Issue: Use of caller-aware methods after Binder.clearCallingIdentity() */
+        @JvmField
+        val ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY: Issue = Issue.create(
+                id = "UseOfCallerAwareMethodsWithClearedIdentity",
+                briefDescription = "Use of caller-aware methods after " +
+                        "Binder.clearCallingIdentity()",
+                explanation = """
+                    You cleared the original calling identity with \
+                    `Binder.clearCallingIdentity()`, but used one of the methods below before \
+                    restoring the identity. These methods will use your own identity instead of \
+                    the caller's identity, so if this is expected replace them with methods that \
+                    explicitly query your own identity such as `Process.myUid()`, \
+                    `Process.myPid()` and `UserHandle.myUserId()`, otherwise move those methods \
+                    out of the `Binder.clearCallingIdentity()` / `Binder.restoreCallingIdentity()` \
+                    section.
+
+                    ```
+                    Binder.getCallingPid()
+                    Binder.getCallingUid()
+                    Binder.getCallingUidOrThrow()
+                    Binder.getCallingUserHandle()
+                    UserHandle.getCallingAppId()
+                    UserHandle.getCallingUserId()
+                    ```
+                    """,
+                category = Category.SECURITY,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingIdentityTokenDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        private fun getIncidentMessageUseOfCallerAwareMethodsWithClearedIdentity(
+            variableName: String,
+            methodName: String
+        ): String = "You cleared the original identity with `Binder.clearCallingIdentity()` " +
+                "and returned into `$variableName`, so `$methodName` will be using your own " +
+                "identity instead of the caller's. Either explicitly query your own identity or " +
+                "move it after restoring the identity with " +
+                "`Binder.restoreCallingIdentity($variableName)`."
+    }
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
new file mode 100644
index 0000000..641f337
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Lint Detector that finds issues with improper usages of the non-user getter methods of Settings
+ */
+@Suppress("UnstableApiUsage")
+class CallingSettingsNonUserGetterMethodsDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableMethodNames(): List<String> = listOf(
+            "getString",
+            "getInt",
+            "getLong",
+            "getFloat"
+    )
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        val evaluator = context.evaluator
+        if (evaluator.isMemberInClass(method, "android.provider.Settings.Secure") ||
+                evaluator.isMemberInClass(method, "android.provider.Settings.System")
+        ) {
+            val message = getIncidentMessageNonUserGetterMethods(getMethodSignature(method))
+            context.report(ISSUE_NON_USER_GETTER_CALLED, node, context.getLocation(node), message)
+        }
+    }
+
+    private fun getMethodSignature(method: PsiMethod) =
+            method.containingClass
+                    ?.qualifiedName
+                    ?.let { "$it#${method.name}" }
+                    ?: method.name
+
+    companion object {
+        @JvmField
+        val ISSUE_NON_USER_GETTER_CALLED: Issue = Issue.create(
+                id = "NonUserGetterCalled",
+                briefDescription = "Non-ForUser Getter Method called to Settings",
+                explanation = """
+                    System process should not call the non-ForUser getter methods of \
+                    `Settings.Secure` or `Settings.System`. For example, instead of \
+                    `Settings.Secure.getInt()`, use `Settings.Secure.getIntForUser()` instead. \
+                    This will make sure that the correct Settings value is retrieved.
+                    """,
+                category = Category.CORRECTNESS,
+                priority = 6,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        CallingSettingsNonUserGetterMethodsDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        fun getIncidentMessageNonUserGetterMethods(methodSignature: String) =
+                "`$methodSignature()` called from system process. " +
+                        "Please call `${methodSignature}ForUser()` instead. "
+    }
+}
diff --git a/tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
similarity index 88%
rename from tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt
rename to tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
index 0fd1a76..e1a5c61 100644
--- a/tools/lint/checks/src/test/java/com/android/lint/CallingIdentityTokenDetectorTest.kt
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.lint
+package com.google.android.lint
 
 import com.android.tools.lint.checks.infrastructure.LintDetectorTest
 import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Issue
 
@@ -26,15 +27,16 @@
     override fun getDetector(): Detector = CallingIdentityTokenDetector()
 
     override fun getIssues(): List<Issue> = listOf(
-            CallingIdentityTokenIssueRegistry.ISSUE_UNUSED_TOKEN,
-            CallingIdentityTokenIssueRegistry.ISSUE_NON_FINAL_TOKEN,
-            CallingIdentityTokenIssueRegistry.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
-            CallingIdentityTokenIssueRegistry.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
-            CallingIdentityTokenIssueRegistry
-                    .ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
-            CallingIdentityTokenIssueRegistry.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY
+            CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
+            CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
+            CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+            CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+            CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+            CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY
     )
 
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
     /** No issue scenario */
 
     fun testDoesNotDetectIssuesInCorrectScenario() {
@@ -43,7 +45,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethod() {
                             final long token1 = Binder.clearCallingIdentity();
                             try {
@@ -55,9 +57,14 @@
                             } finally {
                                 android.os.Binder.restoreCallingIdentity(token2);
                             }
+                            final long token3 = clearCallingIdentity();
+                            try {
+                            } finally {
+                                restoreCallingIdentity(token3);
+                            }
                         }
                     }
-                    """
+                   """
                 ).indented(),
                 *stubs
         )
@@ -73,7 +80,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethodImported() {
                             final long token1 = Binder.clearCallingIdentity();
                             try {
@@ -86,6 +93,12 @@
                             } finally {
                             }
                         }
+                        private void testMethodChildOfBinder() {
+                            final long token3 = clearCallingIdentity();
+                            try {
+                            } finally {
+                            }
+                        }
                     }
                     """
                 ).indented(),
@@ -106,7 +119,13 @@
                         remove token2. [UnusedTokenOfOriginalCallingIdentity]
                                 final long token2 = android.os.Binder.clearCallingIdentity();
                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                        0 errors, 2 warnings
+                        src/test/pkg/TestClass1.java:17: Warning: token3 has not been used to \
+                        restore the calling identity. Introduce a try-finally after the \
+                        declaration and call Binder.restoreCallingIdentity(token3) in finally or \
+                        remove token3. [UnusedTokenOfOriginalCallingIdentity]
+                                final long token3 = clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 3 warnings
                         """.addLineContinuation()
                 )
     }
@@ -232,7 +251,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethod() {
                             long token1 = Binder.clearCallingIdentity();
                             try {
@@ -244,6 +263,11 @@
                             } finally {
                                 android.os.Binder.restoreCallingIdentity(token2);
                             }
+                            long token3 = clearCallingIdentity();
+                            try {
+                            } finally {
+                                restoreCallingIdentity(token3);
+                            }
                         }
                     }
                     """
@@ -263,7 +287,12 @@
                         [NonFinalTokenOfOriginalCallingIdentity]
                                 long token2 = android.os.Binder.clearCallingIdentity();
                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                        0 errors, 2 warnings
+                        src/test/pkg/TestClass1.java:15: Warning: token3 is a non-final token from \
+                        Binder.clearCallingIdentity(). Add final keyword to token3. \
+                        [NonFinalTokenOfOriginalCallingIdentity]
+                                long token3 = clearCallingIdentity();
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                        0 errors, 3 warnings
                         """.addLineContinuation()
                 )
     }
@@ -277,16 +306,16 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethod() {
                             final long token1 = Binder.clearCallingIdentity();
                             try {
                                 final long token2 = android.os.Binder.clearCallingIdentity();
                                 try {
-                                    final long token3 = Binder.clearCallingIdentity();
+                                    final long token3 = clearCallingIdentity();
                                     try {
                                     } finally {
-                                        Binder.restoreCallingIdentity(token3);
+                                        restoreCallingIdentity(token3);
                                     }
                                 } finally {
                                     android.os.Binder.restoreCallingIdentity(token2);
@@ -314,8 +343,8 @@
                         been cleared and returned into token1. Move token3 declaration after \
                         restoring the calling identity with Binder.restoreCallingIdentity(token1). \
                         [NestedClearCallingIdentityCalls]
-                                        final long token3 = Binder.clearCallingIdentity();
-                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                        final long token3 = clearCallingIdentity();
+                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             src/test/pkg/TestClass1.java:5: Location of the token1 declaration.
                         0 errors, 2 warnings
                         """.addLineContinuation()
@@ -330,7 +359,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder{
                         private void testMethodNoTry() {
                             final long token = Binder.clearCallingIdentity();
                             Binder.restoreCallingIdentity(token);
@@ -344,10 +373,10 @@
                             }
                         }
                         private void testMethodLocalVariableBetweenClearAndTry() {
-                            final long token = Binder.clearCallingIdentity(), num = 0;
+                            final long token = clearCallingIdentity(), num = 0;
                             try {
                             } finally {
-                                Binder.restoreCallingIdentity(token);
+                                restoreCallingIdentity(token);
                             }
                         }
                         private void testMethodTryCatch() {
@@ -396,8 +425,8 @@
                         to ensure a safe restore of the calling identity by calling \
                         Binder.restoreCallingIdentity(token) and making it an immediate child of \
                         the finally block. [ClearIdentityCallNotFollowedByTryFinally]
-                                final long token = Binder.clearCallingIdentity(), num = 0;
-                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                final long token = clearCallingIdentity(), num = 0;
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:24: Warning: You cleared the calling identity \
                         and returned the result into token, but the next statement is not a \
                         try-finally statement. Define a try-finally block after token declaration \
@@ -427,7 +456,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethodImported() {
                             final long token = Binder.clearCallingIdentity();
                             try {
@@ -444,10 +473,10 @@
                             android.os.Binder.restoreCallingIdentity(token);
                         }
                         private void testMethodRestoreInCatch() {
-                            final long token = Binder.clearCallingIdentity();
+                            final long token = clearCallingIdentity();
                             try {
                             } catch (Exception e) {
-                                Binder.restoreCallingIdentity(token);
+                                restoreCallingIdentity(token);
                             } finally {
                             }
                         }
@@ -478,8 +507,8 @@
                         finally block of the try statement after token declaration. Surround the c\
                         all with finally block and call it unconditionally. \
                         [RestoreIdentityCallNotInFinallyBlock]
-                                    Binder.restoreCallingIdentity(token);
-                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                    restoreCallingIdentity(token);
+                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         0 errors, 3 warnings
                         """.addLineContinuation()
                 )
@@ -491,7 +520,7 @@
                     """
                     package test.pkg;
                     import android.os.Binder;
-                    public class TestClass1 {
+                    public class TestClass1 extends Binder {
                         private void testMethodOutsideFinally() {
                             final long token1 = Binder.clearCallingIdentity();
                             try {
@@ -523,14 +552,10 @@
                                     }
                                 }
                             }
-                            final long token2 = android.os.Binder.clearCallingIdentity();
+                            final long token2 = clearCallingIdentity();
                             try {
                             } finally {
-                                {
-                                    {
-                                        android.os.Binder.restoreCallingIdentity(token2);
-                                    }
-                                }
+                                if (true) restoreCallingIdentity(token2);
                             }
                         }
                     }
@@ -562,13 +587,13 @@
                         [RestoreIdentityCallNotInFinallyBlock]
                                             Binder.restoreCallingIdentity(token1);
                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                        src/test/pkg/TestClass1.java:40: Warning: \
+                        src/test/pkg/TestClass1.java:38: Warning: \
                         Binder.restoreCallingIdentity(token2) is not an immediate child of the \
                         finally block of the try statement after token2 declaration. Surround the \
                         call with finally block and call it unconditionally. \
                         [RestoreIdentityCallNotInFinallyBlock]
-                                            android.os.Binder.restoreCallingIdentity(token2);
-                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                    if (true) restoreCallingIdentity(token2);
+                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         0 errors, 4 warnings
                         """.addLineContinuation()
                 )
@@ -615,7 +640,7 @@
                         """
                         src/test/pkg/TestClass1.java:8: Warning: You cleared the original identity \
                         with Binder.clearCallingIdentity() and returned into token, so \
-                        Binder.getCallingPid() will be using your own identity instead of the \
+                        getCallingPid() will be using your own identity instead of the \
                         caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -623,7 +648,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:9: Warning: You cleared the original identity \
                         with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.Binder.getCallingPid() will be using your own identity instead \
+                        getCallingPid() will be using your own identity instead \
                         of the caller's. Either explicitly query your own identity or move it \
                         after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -631,7 +656,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:10: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        Binder.getCallingUid() will be using your own identity instead of the \
+                        getCallingUid() will be using your own identity instead of the \
                         caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -639,7 +664,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:11: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.Binder.getCallingUid() will be using your own identity instead \
+                        getCallingUid() will be using your own identity instead \
                         of the caller's. Either explicitly query your own identity or move it \
                         after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -647,7 +672,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:12: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        Binder.getCallingUidOrThrow() will be using your own identity instead of \
+                        getCallingUidOrThrow() will be using your own identity instead of \
                         the caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -655,7 +680,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:13: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.Binder.getCallingUidOrThrow() will be using your own identity \
+                        getCallingUidOrThrow() will be using your own identity \
                         instead of the caller's. Either explicitly query your own identity or move \
                         it after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -663,7 +688,7 @@
                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:14: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        Binder.getCallingUserHandle() will be using your own identity instead of \
+                        getCallingUserHandle() will be using your own identity instead of \
                         the caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -671,7 +696,7 @@
                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:15: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.Binder.getCallingUserHandle() will be using your own identity \
+                        getCallingUserHandle() will be using your own identity \
                         instead of the caller's. Either explicitly query your own identity or move \
                         it after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -679,7 +704,7 @@
                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:17: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        UserHandle.getCallingAppId() will be using your own identity instead of \
+                        getCallingAppId() will be using your own identity instead of \
                         the caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -687,7 +712,7 @@
                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:18: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.UserHandle.getCallingAppId() will be using your own identity \
+                        getCallingAppId() will be using your own identity \
                         instead of the caller's. Either explicitly query your own identity or move \
                         it after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -695,7 +720,7 @@
                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:19: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        UserHandle.getCallingUserId() will be using your own identity instead of \
+                        getCallingUserId() will be using your own identity instead of \
                         the caller's. Either explicitly query your own identity or move it after \
                         restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
@@ -703,7 +728,7 @@
                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         src/test/pkg/TestClass1.java:20: Warning: You cleared the original \
                         identity with Binder.clearCallingIdentity() and returned into token, so \
-                        android.os.UserHandle.getCallingUserId() will be using your own identity \
+                        getCallingUserId() will be using your own identity \
                         instead of the caller's. Either explicitly query your own identity or move \
                         it after restoring the identity with Binder.restoreCallingIdentity(token). \
                         [UseOfCallerAwareMethodsWithClearedIdentity]
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
new file mode 100644
index 0000000..1034029
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class CallingSettingsNonUserGetterMethodsIssueDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = CallingSettingsNonUserGetterMethodsDetector()
+
+    override fun getIssues(): List<Issue> = listOf(
+            CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    fun testDoesNotDetectIssues() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.provider.Settings.Secure;
+                    public class TestClass1 {
+                        private void testMethod(Context context) {
+                            final int value = Secure.getIntForUser(context.getContentResolver(),
+                                Settings.Secure.KEY1, 0, 0);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testDetectsNonUserGetterCalledFromSecure() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.provider.Settings.Secure;
+                    public class TestClass1 {
+                        private void testMethod(Context context) {
+                            final int value = Secure.getInt(context.getContentResolver(),
+                                Settings.Secure.KEY1);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: \
+                        android.provider.Settings.Secure#getInt() called from system process. \
+                        Please call android.provider.Settings.Secure#getIntForUser() instead.  \
+                        [NonUserGetterCalled]
+                                final int value = Secure.getInt(context.getContentResolver(),
+                                                  ^
+                        0 errors, 1 warnings
+                        """.addLineContinuation()
+                )
+    }
+    fun testDetectsNonUserGetterCalledFromSystem() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.provider.Settings.System;
+                    public class TestClass1 {
+                        private void testMethod(Context context) {
+                            final float value = System.getFloat(context.getContentResolver(),
+                                Settings.System.KEY1);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: \
+                        android.provider.Settings.System#getFloat() called from system process. \
+                        Please call android.provider.Settings.System#getFloatForUser() instead.  \
+                        [NonUserGetterCalled]
+                                final float value = System.getFloat(context.getContentResolver(),
+                                                    ^
+                        0 errors, 1 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsNonUserGetterCalledFromSettings() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.provider.Settings;
+                    public class TestClass1 {
+                        private void testMethod(Context context) {
+                            float value = Settings.System.getFloat(context.getContentResolver(),
+                                Settings.System.KEY1);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:5: Warning: \
+                        android.provider.Settings.System#getFloat() called from system process. \
+                        Please call android.provider.Settings.System#getFloatForUser() instead.  \
+                        [NonUserGetterCalled]
+                                float value = Settings.System.getFloat(context.getContentResolver(),
+                                              ^
+                        0 errors, 1 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    fun testDetectsNonUserGettersCalledFromSystemAndSecure() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.provider.Settings.Secure;
+                    import android.provider.Settings.System;
+                    public class TestClass1 {
+                        private void testMethod(Context context) {
+                            final long value1 = Secure.getLong(context.getContentResolver(),
+                                Settings.Secure.KEY1, 0);
+                            final String value2 = System.getString(context.getContentResolver(),
+                                Settings.System.KEY2);
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                        """
+                        src/test/pkg/TestClass1.java:6: Warning: \
+                        android.provider.Settings.Secure#getLong() called from system process. \
+                        Please call android.provider.Settings.Secure#getLongForUser() instead.  \
+                        [NonUserGetterCalled]
+                                final long value1 = Secure.getLong(context.getContentResolver(),
+                                                    ^
+                        src/test/pkg/TestClass1.java:8: Warning: \
+                        android.provider.Settings.System#getString() called from system process. \
+                        Please call android.provider.Settings.System#getStringForUser() instead.  \
+                        [NonUserGetterCalled]
+                                final String value2 = System.getString(context.getContentResolver(),
+                                                      ^
+                        0 errors, 2 warnings
+                        """.addLineContinuation()
+                )
+    }
+
+    private val SettingsStub: TestFile = java(
+            """
+            package android.provider;
+            public class Settings {
+                public class Secure {
+                    float getFloat(ContentResolver cr, String key) {
+                        return 0.0f;
+                    }
+                    long getLong(ContentResolver cr, String key) {
+                        return 0l;
+                    }
+                    int getInt(ContentResolver cr, String key) {
+                        return 0;
+                    }
+                }
+                public class System {
+                    float getFloat(ContentResolver cr, String key) {
+                        return 0.0f;
+                    }
+                    long getLong(ContentResolver cr, String key) {
+                        return 0l;
+                    }
+                    String getString(ContentResolver cr, String key) {
+                        return null;
+                    }
+                }
+            }
+            """
+    ).indented()
+
+    private val stubs = arrayOf(SettingsStub)
+
+    // Substitutes "backslash + new line" with an empty string to imitate line continuation
+    private fun String.addLineContinuation(): String = this.trimIndent().replace("\\\n", "")
+}